diff --git a/.all-contributorsrc b/.all-contributorsrc index 27fa03dad..998a274c9 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -766,6 +766,150 @@ "contributions": [ "code" ] + }, + { + "login": "nnnlog", + "name": "nlog (solrin)", + "avatar_url": "https://avatars.githubusercontent.com/u/20399222?v=4", + "profile": "https://nlog.dev", + "contributions": [ + "code" + ] + }, + { + "login": "Murmurl912", + "name": "Murmurl912", + "avatar_url": "https://avatars.githubusercontent.com/u/36264246?v=4", + "profile": "https://github.com/Murmurl912", + "contributions": [ + "code" + ] + }, + { + "login": "bschulz87", + "name": "Benjamin Schulz", + "avatar_url": "https://avatars.githubusercontent.com/u/30199362?v=4", + "profile": "https://github.com/bschulz87", + "contributions": [ + "ideas" + ] + }, + { + "login": "ShuheiSuzuki-07", + "name": "seal-app", + "avatar_url": "https://avatars.githubusercontent.com/u/118415919?v=4", + "profile": "https://github.com/ShuheiSuzuki-07", + "contributions": [ + "code" + ] + }, + { + "login": "takuyaaaaaaahaaaaaa", + "name": "Takuya Tominaga", + "avatar_url": "https://avatars.githubusercontent.com/u/31458194?v=4", + "profile": "https://github.com/takuyaaaaaaahaaaaaa", + "contributions": [ + "code" + ] + }, + { + "login": "yamaha252", + "name": "Sergey", + "avatar_url": "https://avatars.githubusercontent.com/u/4444068?v=4", + "profile": "https://github.com/yamaha252", + "contributions": [ + "code" + ] + }, + { + "login": "lyb5834", + "name": "yuanbo li", + "avatar_url": "https://avatars.githubusercontent.com/u/16265810?v=4", + "profile": "https://github.com/lyb5834", + "contributions": [ + "code" + ] + }, + { + "login": "Mecharyry", + "name": "Ryan Feline", + "avatar_url": "https://avatars.githubusercontent.com/u/3380092?v=4", + "profile": "https://github.com/Mecharyry", + "contributions": [ + "code" + ] + }, + { + "login": "fuzzybinary", + "name": "Jeff Ward", + "avatar_url": "https://avatars.githubusercontent.com/u/249982?v=4", + "profile": "https://fuzzybinary.com", + "contributions": [ + "test" + ] + }, + { + "login": "yerkejs", + "name": "Yelzhan Yerkebulan", + "avatar_url": "https://avatars.githubusercontent.com/u/33483071?v=4", + "profile": "https://hero.io", + "contributions": [ + "code" + ] + }, + { + "login": "GooRingX", + "name": "GooRingX", + "avatar_url": "https://avatars.githubusercontent.com/u/167741400?v=4", + "profile": "https://github.com/GooRingX", + "contributions": [ + "code" + ] + }, + { + "login": "roberthofstra", + "name": "Robodoh", + "avatar_url": "https://avatars.githubusercontent.com/u/1643242?v=4", + "profile": "https://github.com/roberthofstra", + "contributions": [ + "code" + ] + }, + { + "login": "imoyakin", + "name": "imoyakin", + "avatar_url": "https://avatars.githubusercontent.com/u/7473806?v=4", + "profile": "https://github.com/imoyakin", + "contributions": [ + "code" + ] + }, + { + "login": "laishere", + "name": "laishere", + "avatar_url": "https://avatars.githubusercontent.com/u/23557738?v=4", + "profile": "https://github.com/laishere", + "contributions": [ + "code" + ] + }, + { + "login": "muccy-timeware", + "name": "Marco Muccinelli", + "avatar_url": "https://avatars.githubusercontent.com/u/74927063?v=4", + "profile": "https://github.com/muccy-timeware", + "contributions": [ + "code" + ] + }, + { + "login": "momadvisor", + "name": "momadvisor", + "avatar_url": "https://avatars.githubusercontent.com/u/77181890?v=4", + "profile": "https://github.com/momadvisor", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 000000000..d2e77e2ca --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,187 @@ +# GitHub Copilot Instructions — flutter_inappwebview + +You are an expert Flutter and Dart plugin developer, specializing in the `flutter_inappwebview` plugin architecture. +Use these notes whenever you propose code for this repository. + +## Architecture Overview + +This repository follows the **Federated Plugin** architecture: + +- **`flutter_inappwebview/`**: The **app-facing package**. This is the public API that developers depend on. + - Files here usually wrap platform implementations via `Platform*` classes (e.g., `PlatformInAppWebViewWidget`). + - It delegates logic to the platform interface or specific platform implementations. +- **`flutter_inappwebview_platform_interface/`**: The **platform interface package**. + - Contains pure Dart contracts, typedefs, enums, and shared utilities. + - Defines the `PlatformInterface` that all platform packages must implement. + - **Crucial**: Anything added to the public API (`flutter_inappwebview`) MUST rely on or extend these definitions. DO NOT duplicate platform logic in the public package. +- **`flutter_inappwebview_/`**: The **platform implementation packages** (Android, iOS, macOS, Windows, Web). + - These packages implement the abstract classes defined in `flutter_inappwebview_platform_interface`. + - They contain platform-specific code (Dart and native: Java/Kotlin, Obj-C/Swift, C++, JavaScript). + - Keep their APIs strictly aligned with the `platform_interface` layer. +- **`dev_packages/` and `scripts/`**: Internal tooling, generators, and maintenance scripts. + +### Main App-Facing Classes +- Web view: `InAppWebView`, `InAppWebViewController`, `HeadlessInAppWebView` +- Browser shells: `InAppBrowser`, `ChromeSafariBrowser`, `WebAuthenticationSession` +- Platform helpers: `WebViewEnvironment`, `ProcessGlobalConfig`, `ProxyController`, `ServiceWorkerController`, `TracingController`, `PrintJobController`, `PullToRefreshController`, `FindInteractionController` +- Storage & messaging: `WebStorage`, `LocalStorage`, `SessionStorage`, `WebStorageManager`, `WebMessageChannel`, `WebMessageListener` +- Cookies: `CookieManager` +- Auth storage: `HttpAuthCredentialDatabase` + +### InAppWebViewSettings quick reference +- Source of truth: `flutter_inappwebview_platform_interface/lib/src/in_app_webview/in_app_webview_settings.dart` (`InAppWebViewSettings_` with `@ExchangeableObject` → generated public `InAppWebViewSettings`). Always edit the annotated source, then run `npm run build` to regenerate `*.g.dart`. +- Role: exhaustive configuration bag for `InAppWebView`/`InAppBrowser` creation params. Mirrors platform capabilities via `@SupportedPlatforms` on each field; no platform-specific logic belongs here. +- Defaults/inference: several flags (e.g., `useShouldOverrideUrlLoading`, `useOnLoadResource`, `useShouldInterceptRequest`, AJAX/fetch hooks) auto-infer to `true` when the related callback is implemented and the flag is `null`. Set explicitly in browsers to avoid surprises. +- Deprecated fields: keep deprecated properties tagged with `@ExchangeableObjectProperty(leaveDeprecatedInToMapMethod: true)` so serialization remains backward compatible. Prefer new alternatives (e.g., `algorithmicDarkeningAllowed` over `forceDark`). +- Complex types: uses exchangeable enums/objects such as `MixedContentMode_`, `WebViewAssetLoader_`, `RendererPriorityPolicy_`, `ContentBlocker`. Add new fields only after defining the enum/object in `platform_interface` and regenerating code. +- Support checks: rely on generated support helpers; when adding a field, annotate with `@SupportedPlatforms` and ensure downstream platform packages handle the field (or stub it) to preserve parity. + +## Coding Guidelines + +### General +- **Stay Dart-side unless explicitly working inside a platform package.** Never touch native (`.java`, `.kt`, `.mm`, `.swift`, `.cpp`, `.cs`) code when an issue only concerns the shared Dart API. +- **Null Safety**: Strictly adhere to null safety. Do not introduce nullable APIs unless absolutely necessary. Prefer optional named parameters with sensible defaults. +- **Avoid Breaking Changes**: In the public package (`flutter_inappwebview`), avoid breaking changes. Any API change requires updating the `platform_interface`, all federated implementations, and changelog entries. +- **Code Generation**: Use `@ExchangeableObject`, `@ExchangeableEnum`, and other annotations from `flutter_inappwebview_internal_annotations` to generate boilerplate code (e.g., `toMap`, `fromMap`, `copy`). Run `dart run build_runner build` to regenerate files. +- **Generated Files**: Never hand-edit generated artifacts (for example `*.g.dart`). Update the annotated source instead, rerun `dart run build_runner build`, and include only the regenerated outputs relevant to your change. + +### Platform Interface & Public API +- **Constructor Helpers**: When exposing new public classes in `flutter_inappwebview`, prefer constructor helpers like `fromPlatformCreationParams` and `fromPlatform`. This allows downstream packages to inject platform overrides. +- **Documentation Macros**: Respect documentation macros (`{@macro ...}`) and keep comments synchronized with definitions in the `platform_interface` package. +- **`@SupportedPlatforms`**: Add `@SupportedPlatforms` annotations that mirror the contract comments in `platform_interface`. Only mark a platform supported when the corresponding federated implementation actually exists. + - **Parameters**: + - `platforms`: List of `Platform` objects (e.g., `AndroidPlatform`, `IOSPlatform`). + - **Platform Object Parameters**: + - `available`: Version string when the feature became available (e.g., "21"). + - `apiName`: Name of the underlying native API (e.g., "View.setAlpha"). + - `apiUrl`: URL to the official native documentation. + - `note`: Special notes or restrictions. +- **Support Checks**: Implement support-check helpers (`isClassSupported`, `isPropertySupported`, `isMethodSupported`) by deferring to the `platform_interface` static singleton (`PlatformX.static()`). +- **Static-only Helpers**: If a class only exposes static helpers (no instance properties/methods), you can skip overriding `isPropertySupported`/`isMethodSupported` altogether; make sure the public wrapper still calls the static singleton when exposing support checks. +- **Enums & Types**: Keep enums for methods/properties in the `platform_interface` package. The public package should use simple passthrough helpers. +- **Propagation Order**: Add or change APIs in `flutter_inappwebview_platform_interface` first, then update every `flutter_inappwebview_` implementation, and finally wire the public `flutter_inappwebview` wrapper. Each touched package needs an aligned changelog entry. + +### Supported Platforms Pattern +When implementing a new platform interface class (e.g., `PlatformWebViewEnvironment`), follow this strict pattern to ensure correct documentation generation and runtime support checks: + +1. **Creation Params Class (`Platform*CreationParams`)**: + - Define the property documentation using `{@template ...}`. + - Apply the `@SupportedPlatforms` annotation to the property here. + - Implement `isClassSupported`, implement `isPropertySupported` if the class has properties, and `isMethodSupported` if the class has methods. + - **Crucial**: `isPropertySupported` must accept `dynamic property` and check if the property name exists in the `CreationParams` class first. + + ```dart + @SupportedPlatforms(platforms: [WindowsPlatform()]) + @immutable + class PlatformWebViewEnvironmentCreationParams { + const PlatformWebViewEnvironmentCreationParams({this.settings}); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironmentCreationParams.settings} + /// WebView Environment settings. + ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironmentCreationParams.settings.supported_platforms} + @SupportedPlatforms(platforms: [WindowsPlatform()]) + final WebViewEnvironmentSettings? settings; + + bool isClassSupported({TargetPlatform? platform}) => + PlatformWebViewEnvironment.isClassSupported(platform: platform); + + bool isPropertySupported(dynamic property, {TargetPlatform? platform}) => + PlatformWebViewEnvironment.isPropertySupported(property, platform: platform); + } + ``` + +2. **Main Interface Class (`Platform*`)**: + - Use `{@macro ...}` to reuse the documentation from `CreationParams`. + - **Do NOT** repeat `@SupportedPlatforms` on the getters/properties in this class. The macro will pull the supported platforms documentation. + - Implement `isClassSupported`, `isPropertySupported`, and `isMethodSupported` instance methods (which are called by the static singleton). + - **Crucial**: `isPropertySupported` and `isMethodSupported` should ONLY be implemented if the class actually has properties or methods to check. If the class has no properties, do not implement `isPropertySupported`. If it has no methods, do not implement `isMethodSupported`. + - **Crucial**: `isPropertySupported` must handle both `CreationParams` properties and the class's own properties (using the generated `*CreationParamsProperty` and `*PropertySupported` classes). + - **Crucial**: `isMethodSupported` delegates to the generated `_Platform*MethodSupported` class. + - **Reference Implementations**: `PlatformPrintJobController` shows the full property+method pattern, `PlatformFindInteractionController` shows params-only property forwarding, and `PlatformCookieManager` mixes environment-specific params with method support. + + ```dart + @SupportedPlatforms(platforms: [WindowsPlatform()]) + abstract class PlatformWebViewEnvironment extends PlatformInterface implements Disposable { + // ... factory constructors ... + + ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironmentCreationParams.settings} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironmentCreationParams.settings.supported_platforms} + WebViewEnvironmentSettings? get settings => params.settings; + + ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironmentCreationParams.isClassSupported} + bool isClassSupported({TargetPlatform? platform}) => + params.isClassSupported(platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.isPropertySupported} + ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isPropertySupported(dynamic property, {TargetPlatform? platform}) => + property is PlatformWebViewEnvironmentCreationParamsProperty + ? params.isPropertySupported(property, platform: platform) + : _PlatformWebViewEnvironmentPropertySupported.isPropertySupported( + property, + platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.isMethodSupported} + ///Check if the given [method] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isMethodSupported(PlatformWebViewEnvironmentMethod method, + {TargetPlatform? platform}) => + _PlatformWebViewEnvironmentMethodSupported.isMethodSupported(method, + platform: platform); + } + ``` + +### Platform Implementations +- **`inappwebview_platform.dart`**: This file in each platform package implements `InAppWebViewPlatform` and handles the creation of platform-specific classes (e.g., `createPlatformInAppWebViewController`). +- **Unsupported Features**: If a feature is NOT supported on a specific platform, you must still implement the creation method in `inappwebview_platform.dart`. Return an instance of a private empty class (e.g., `class _PlatformProcessGlobalConfig extends PlatformProcessGlobalConfig`) that extends the platform interface class. This ensures `isClassSupported`, `isPropertySupported`, `isMethodSupported` static methods works correctly via the `@SupportedPlatforms` annotation. +- **Extending Params**: Platform implementations should extend `Platform*CreationParams` (e.g., `AndroidInAppWebViewWidgetCreationParams` extends `PlatformInAppWebViewWidgetCreationParams`) to add platform-specific fields. +- **Platform Views**: + - **Android**: Uses `PlatformViewLink` and `AndroidViewSurface` (or `AndroidView` for simple cases) to render native views; [android.webkit.WebView](https://developer.android.com/reference/android/webkit/WebView). + - **iOS**: Uses `UiKitView`; [WKWebView](https://developer.apple.com/documentation/webkit/wkwebview). + - **macOS**: Uses `AppKitView`; [WKWebView](https://developer.apple.com/documentation/webkit/wkwebview). + - **Windows**: Uses a custom platform view implementation using textures; [WebView2](https://learn.microsoft.com/en-us/microsoft-edge/webview2/). + - **Web**: Uses an `HtmlElementView` to embed an `. + @SupportedPlatforms(platforms: [ + WindowsPlatform(), + ]) + String? name; + + ///The unique identifier of the frame associated with the current [FrameInfo]. + @SupportedPlatforms(platforms: [ + WindowsPlatform(), + ]) + int? frameId; + + ///The kind of the frame. + @SupportedPlatforms(platforms: [ + WindowsPlatform(), + ]) + FrameKind_? kind; + FrameInfo_( - {required this.isMainFrame, required this.request, this.securityOrigin}); + {required this.isMainFrame, + required this.request, + this.securityOrigin, + this.name, + this.frameId, + this.kind}); } ///An object that contains information about a frame on a webpage. diff --git a/flutter_inappwebview_platform_interface/lib/src/types/frame_info.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/frame_info.g.dart index 71f0402a5..a2dc3f36b 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/frame_info.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/frame_info.g.dart @@ -8,36 +8,92 @@ part of 'frame_info.dart'; ///An object that contains information about a frame on a webpage. class FrameInfo { + ///The unique identifier of the frame associated with the current [FrameInfo]. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 + int? frameId; + ///A Boolean value indicating whether the frame is the web site's main frame or a subframe. + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView + ///- macOS WKWebView + ///- Windows WebView2 bool isMainFrame; + ///The kind of the frame. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 + FrameKind? kind; + + ///Gets the name attribute of the frame, as in . + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 + String? name; + ///The frame’s current request. + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView + ///- macOS WKWebView + ///- Windows WebView2 URLRequest? request; ///The frame’s security origin. + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView + ///- macOS WKWebView + ///- Windows WebView2 SecurityOrigin? securityOrigin; - FrameInfo({required this.isMainFrame, this.request, this.securityOrigin}); + FrameInfo( + {this.frameId, + required this.isMainFrame, + this.kind, + this.name, + this.request, + this.securityOrigin}); ///Gets a possible [FrameInfo] instance from a [Map] value. - static FrameInfo? fromMap(Map? map) { + static FrameInfo? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = FrameInfo( + frameId: map['frameId'], isMainFrame: map['isMainFrame'], - request: URLRequest.fromMap(map['request']?.cast()), + kind: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => FrameKind.fromNativeValue(map['kind']), + EnumMethod.value => FrameKind.fromValue(map['kind']), + EnumMethod.name => FrameKind.byName(map['kind']) + }, + name: map['name'], + request: URLRequest.fromMap(map['request']?.cast(), + enumMethod: enumMethod), securityOrigin: SecurityOrigin.fromMap( - map['securityOrigin']?.cast()), + map['securityOrigin']?.cast(), + enumMethod: enumMethod), ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { + "frameId": frameId, "isMainFrame": isMainFrame, - "request": request?.toMap(), - "securityOrigin": securityOrigin?.toMap(), + "kind": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => kind?.toNativeValue(), + EnumMethod.value => kind?.toValue(), + EnumMethod.name => kind?.name() + }, + "name": name, + "request": request?.toMap(enumMethod: enumMethod), + "securityOrigin": securityOrigin?.toMap(enumMethod: enumMethod), }; } @@ -48,7 +104,7 @@ class FrameInfo { @override String toString() { - return 'FrameInfo{isMainFrame: $isMainFrame, request: $request, securityOrigin: $securityOrigin}'; + return 'FrameInfo{frameId: $frameId, isMainFrame: $isMainFrame, kind: $kind, name: $name, request: $request, securityOrigin: $securityOrigin}'; } } @@ -71,25 +127,28 @@ class IOSWKFrameInfo { {required this.isMainFrame, this.request, this.securityOrigin}); ///Gets a possible [IOSWKFrameInfo] instance from a [Map] value. - static IOSWKFrameInfo? fromMap(Map? map) { + static IOSWKFrameInfo? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = IOSWKFrameInfo( isMainFrame: map['isMainFrame'], - request: URLRequest.fromMap(map['request']?.cast()), + request: URLRequest.fromMap(map['request']?.cast(), + enumMethod: enumMethod), securityOrigin: IOSWKSecurityOrigin.fromMap( - map['securityOrigin']?.cast()), + map['securityOrigin']?.cast(), + enumMethod: enumMethod), ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "isMainFrame": isMainFrame, - "request": request?.toMap(), - "securityOrigin": securityOrigin?.toMap(), + "request": request?.toMap(enumMethod: enumMethod), + "securityOrigin": securityOrigin?.toMap(enumMethod: enumMethod), }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/frame_kind.dart b/flutter_inappwebview_platform_interface/lib/src/types/frame_kind.dart new file mode 100644 index 000000000..a4afe1575 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/frame_kind.dart @@ -0,0 +1,64 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +part 'frame_kind.g.dart'; + +///Class used to indicate the the frame kind. +@ExchangeableEnum() +class FrameKind_ { + // ignore: unused_field + final String _value; + // ignore: unused_field + final int? _nativeValue = null; + const FrameKind_._internal(this._value); + + ///Indicates that the frame is an unknown type frame. We may extend this enum type to identify more frame kinds in the future. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_FRAME_KIND_UNKNOWN', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', + value: 0), + ]) + static const UNKNOWN = const FrameKind_._internal('UNKNOWN'); + + ///Indicates that the frame is a primary main frame(webview). + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_FRAME_KIND_MAIN_FRAME', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', + value: 1), + ]) + static const MAIN_FRAME = const FrameKind_._internal('MAIN_FRAME'); + + ///Indicates that the frame is an iframe. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_FRAME_KIND_IFRAME', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', + value: 2), + ]) + static const IFRAME = const FrameKind_._internal('IFRAME'); + + ///Indicates that the frame is an embed element. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_FRAME_KIND_EMBED', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', + value: 3), + ]) + static const EMBED = const FrameKind_._internal('EMBED'); + + ///Indicates that the frame is an object element. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_FRAME_KIND_OBJECT', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind', + value: 4), + ]) + static const OBJECT = const FrameKind_._internal('OBJECT'); +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/frame_kind.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/frame_kind.g.dart new file mode 100644 index 000000000..0c47a6451 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/frame_kind.g.dart @@ -0,0 +1,190 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'frame_kind.dart'; + +// ************************************************************************** +// ExchangeableEnumGenerator +// ************************************************************************** + +///Class used to indicate the the frame kind. +class FrameKind { + final String _value; + final int? _nativeValue; + const FrameKind._internal(this._value, this._nativeValue); +// ignore: unused_element + factory FrameKind._internalMultiPlatform( + String value, Function nativeValue) => + FrameKind._internal(value, nativeValue()); + + ///Indicates that the frame is an embed element. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_FRAME_KIND_EMBED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind)) + static final EMBED = FrameKind._internalMultiPlatform('EMBED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 3; + default: + break; + } + return null; + }); + + ///Indicates that the frame is an iframe. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_FRAME_KIND_IFRAME](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind)) + static final IFRAME = FrameKind._internalMultiPlatform('IFRAME', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 2; + default: + break; + } + return null; + }); + + ///Indicates that the frame is a primary main frame(webview). + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_FRAME_KIND_MAIN_FRAME](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind)) + static final MAIN_FRAME = FrameKind._internalMultiPlatform('MAIN_FRAME', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 1; + default: + break; + } + return null; + }); + + ///Indicates that the frame is an object element. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_FRAME_KIND_OBJECT](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind)) + static final OBJECT = FrameKind._internalMultiPlatform('OBJECT', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 4; + default: + break; + } + return null; + }); + + ///Indicates that the frame is an unknown type frame. We may extend this enum type to identify more frame kinds in the future. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_FRAME_KIND_UNKNOWN](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_frame_kind)) + static final UNKNOWN = FrameKind._internalMultiPlatform('UNKNOWN', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 0; + default: + break; + } + return null; + }); + + ///Set of all values of [FrameKind]. + static final Set values = [ + FrameKind.EMBED, + FrameKind.IFRAME, + FrameKind.MAIN_FRAME, + FrameKind.OBJECT, + FrameKind.UNKNOWN, + ].toSet(); + + ///Gets a possible [FrameKind] instance from [String] value. + static FrameKind? fromValue(String? value) { + if (value != null) { + try { + return FrameKind.values + .firstWhere((element) => element.toValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + ///Gets a possible [FrameKind] instance from a native value. + static FrameKind? fromNativeValue(int? value) { + if (value != null) { + try { + return FrameKind.values + .firstWhere((element) => element.toNativeValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + /// Gets a possible [FrameKind] instance value with name [name]. + /// + /// Goes through [FrameKind.values] looking for a value with + /// name [name], as reported by [FrameKind.name]. + /// Returns the first value with the given name, otherwise `null`. + static FrameKind? byName(String? name) { + if (name != null) { + try { + return FrameKind.values.firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [FrameKind] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in FrameKind.values) value.name(): value + }; + + ///Gets [String] value. + String toValue() => _value; + + ///Gets [int] native value if supported by the current platform, otherwise `null`. + int? toNativeValue() => _nativeValue; + + ///Gets the name of the value. + String name() { + switch (_value) { + case 'EMBED': + return 'EMBED'; + case 'IFRAME': + return 'IFRAME'; + case 'MAIN_FRAME': + return 'MAIN_FRAME'; + case 'OBJECT': + return 'OBJECT'; + case 'UNKNOWN': + return 'UNKNOWN'; + } + return _value.toString(); + } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + + @override + String toString() { + return _value; + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/geolocation_permission_show_prompt_response.dart b/flutter_inappwebview_platform_interface/lib/src/types/geolocation_permission_show_prompt_response.dart index fa4cd16d6..b7ff1e847 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/geolocation_permission_show_prompt_response.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/geolocation_permission_show_prompt_response.dart @@ -1,5 +1,8 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + import '../in_app_webview/platform_webview.dart'; +import 'enum_method.dart'; + part 'geolocation_permission_show_prompt_response.g.dart'; ///Class used by the host application to set the Geolocation permission state for an origin during the [PlatformWebViewCreationParams.onGeolocationPermissionsShowPrompt] event. diff --git a/flutter_inappwebview_platform_interface/lib/src/types/geolocation_permission_show_prompt_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/geolocation_permission_show_prompt_response.g.dart index 37be906a5..d2d98a9cf 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/geolocation_permission_show_prompt_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/geolocation_permission_show_prompt_response.g.dart @@ -22,7 +22,8 @@ class GeolocationPermissionShowPromptResponse { ///Gets a possible [GeolocationPermissionShowPromptResponse] instance from a [Map] value. static GeolocationPermissionShowPromptResponse? fromMap( - Map? map) { + Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -30,12 +31,14 @@ class GeolocationPermissionShowPromptResponse { allow: map['allow'], origin: map['origin'], ); - instance.retain = map['retain']; + if (map['retain'] != null) { + instance.retain = map['retain']; + } return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "allow": allow, "origin": origin, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response.dart b/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response.dart index ce0340eb9..1f06fd0ce 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response.dart @@ -1,6 +1,8 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + import '../in_app_webview/platform_webview.dart'; import 'http_auth_response_action.dart'; +import 'enum_method.dart'; part 'http_auth_response.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response.g.dart index dfa18193a..0cf972f32 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response.g.dart @@ -26,22 +26,38 @@ class HttpAuthResponse { this.username = ""}); ///Gets a possible [HttpAuthResponse] instance from a [Map] value. - static HttpAuthResponse? fromMap(Map? map) { + static HttpAuthResponse? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = HttpAuthResponse(); - instance.action = HttpAuthResponseAction.fromNativeValue(map['action']); - instance.password = map['password']; - instance.permanentPersistence = map['permanentPersistence']; - instance.username = map['username']; + instance.action = switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + HttpAuthResponseAction.fromNativeValue(map['action']), + EnumMethod.value => HttpAuthResponseAction.fromValue(map['action']), + EnumMethod.name => HttpAuthResponseAction.byName(map['action']) + }; + if (map['password'] != null) { + instance.password = map['password']; + } + if (map['permanentPersistence'] != null) { + instance.permanentPersistence = map['permanentPersistence']; + } + if (map['username'] != null) { + instance.username = map['username']; + } return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "action": action?.toNativeValue(), + "action": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => action?.toNativeValue(), + EnumMethod.value => action?.toValue(), + EnumMethod.name => action?.name() + }, "password": password, "permanentPersistence": permanentPersistence, "username": username, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response_action.dart b/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response_action.dart index dbd5c5871..1199a0dca 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response_action.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response_action.dart @@ -12,12 +12,29 @@ class HttpAuthResponseAction_ { const HttpAuthResponseAction_._internal(this._value); ///Instructs the WebView to cancel the authentication request. + @EnumSupportedPlatforms(platforms: [ + EnumAndroidPlatform(), + EnumIOSPlatform(), + EnumMacOSPlatform(), + EnumWindowsPlatform(), + ]) static const CANCEL = const HttpAuthResponseAction_._internal(0); ///Instructs the WebView to proceed with the authentication with the given credentials. + @EnumSupportedPlatforms(platforms: [ + EnumAndroidPlatform(), + EnumIOSPlatform(), + EnumMacOSPlatform(), + EnumWindowsPlatform(), + ]) static const PROCEED = const HttpAuthResponseAction_._internal(1); ///Uses the credentials stored for the current host. + @EnumSupportedPlatforms(platforms: [ + EnumAndroidPlatform(), + EnumIOSPlatform(), + EnumMacOSPlatform(), + ]) static const USE_SAVED_HTTP_AUTH_CREDENTIALS = const HttpAuthResponseAction_._internal(2); } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response_action.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response_action.g.dart index 320124311..192ff0dda 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response_action.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/http_auth_response_action.g.dart @@ -17,12 +17,29 @@ class HttpAuthResponseAction { HttpAuthResponseAction._internal(value, nativeValue()); ///Instructs the WebView to cancel the authentication request. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Windows WebView2 static const CANCEL = HttpAuthResponseAction._internal(0, 0); ///Instructs the WebView to proceed with the authentication with the given credentials. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Windows WebView2 static const PROCEED = HttpAuthResponseAction._internal(1, 1); ///Uses the credentials stored for the current host. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView static const USE_SAVED_HTTP_AUTH_CREDENTIALS = HttpAuthResponseAction._internal(2, 2); @@ -59,20 +76,44 @@ class HttpAuthResponseAction { return null; } + /// Gets a possible [HttpAuthResponseAction] instance value with name [name]. + /// + /// Goes through [HttpAuthResponseAction.values] looking for a value with + /// name [name], as reported by [HttpAuthResponseAction.name]. + /// Returns the first value with the given name, otherwise `null`. + static HttpAuthResponseAction? byName(String? name) { + if (name != null) { + try { + return HttpAuthResponseAction.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [HttpAuthResponseAction] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in HttpAuthResponseAction.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 0: return 'CANCEL'; @@ -83,4 +124,20 @@ class HttpAuthResponseAction { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/http_authentication_challenge.dart b/flutter_inappwebview_platform_interface/lib/src/types/http_authentication_challenge.dart index 227ae10da..eb7dcc944 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/http_authentication_challenge.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/http_authentication_challenge.dart @@ -5,6 +5,7 @@ import 'url_response.dart'; import 'url_authentication_challenge.dart'; import 'url_protection_space.dart'; import '../in_app_webview/platform_webview.dart'; +import 'enum_method.dart'; part 'http_authentication_challenge.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/http_authentication_challenge.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/http_authentication_challenge.g.dart index 3481661d9..947d84e85 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/http_authentication_challenge.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/http_authentication_challenge.g.dart @@ -54,34 +54,39 @@ class HttpAuthenticationChallenge extends URLAuthenticationChallenge { } ///Gets a possible [HttpAuthenticationChallenge] instance from a [Map] value. - static HttpAuthenticationChallenge? fromMap(Map? map) { + static HttpAuthenticationChallenge? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = HttpAuthenticationChallenge( protectionSpace: URLProtectionSpace.fromMap( - map['protectionSpace']?.cast())!, + map['protectionSpace']?.cast(), + enumMethod: enumMethod)!, error: map['error'], - failureResponse: - URLResponse.fromMap(map['failureResponse']?.cast()), + failureResponse: URLResponse.fromMap( + map['failureResponse']?.cast(), + enumMethod: enumMethod), iosError: map['error'], iosFailureResponse: IOSURLResponse.fromMap( - map['failureResponse']?.cast()), + map['failureResponse']?.cast(), + enumMethod: enumMethod), previousFailureCount: map['previousFailureCount'], proposedCredential: URLCredential.fromMap( - map['proposedCredential']?.cast()), + map['proposedCredential']?.cast(), + enumMethod: enumMethod), ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "protectionSpace": protectionSpace.toMap(), + "protectionSpace": protectionSpace.toMap(enumMethod: enumMethod), "error": error, - "failureResponse": failureResponse?.toMap(), + "failureResponse": failureResponse?.toMap(enumMethod: enumMethod), "previousFailureCount": previousFailureCount, - "proposedCredential": proposedCredential?.toMap(), + "proposedCredential": proposedCredential?.toMap(enumMethod: enumMethod), }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/http_cookie_same_site_policy.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/http_cookie_same_site_policy.g.dart index c21d5381b..980fde6b0 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/http_cookie_same_site_policy.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/http_cookie_same_site_policy.g.dart @@ -66,18 +66,66 @@ class HTTPCookieSameSitePolicy { return null; } + /// Gets a possible [HTTPCookieSameSitePolicy] instance value with name [name]. + /// + /// Goes through [HTTPCookieSameSitePolicy.values] looking for a value with + /// name [name], as reported by [HTTPCookieSameSitePolicy.name]. + /// Returns the first value with the given name, otherwise `null`. + static HTTPCookieSameSitePolicy? byName(String? name) { + if (name != null) { + try { + return HTTPCookieSameSitePolicy.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [HTTPCookieSameSitePolicy] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in HTTPCookieSameSitePolicy.values) value.name(): value + }; + ///Gets [String] value. String toValue() => _value; ///Gets [String] native value. String toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'Lax': + return 'LAX'; + case 'None': + return 'NONE'; + case 'Strict': + return 'STRICT'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { return _value; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_hit_test_result.dart b/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_hit_test_result.dart index cd5836305..7299bec02 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_hit_test_result.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_hit_test_result.dart @@ -1,6 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import 'in_app_webview_hit_test_result_type.dart'; +import 'enum_method.dart'; part 'in_app_webview_hit_test_result.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_hit_test_result.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_hit_test_result.g.dart index c022ecffe..5e719439f 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_hit_test_result.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_hit_test_result.g.dart @@ -16,22 +16,33 @@ class InAppWebViewHitTestResult { InAppWebViewHitTestResult({this.extra, this.type}); ///Gets a possible [InAppWebViewHitTestResult] instance from a [Map] value. - static InAppWebViewHitTestResult? fromMap(Map? map) { + static InAppWebViewHitTestResult? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = InAppWebViewHitTestResult( extra: map['extra'], - type: InAppWebViewHitTestResultType.fromNativeValue(map['type']), + type: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + InAppWebViewHitTestResultType.fromNativeValue(map['type']), + EnumMethod.value => + InAppWebViewHitTestResultType.fromValue(map['type']), + EnumMethod.name => InAppWebViewHitTestResultType.byName(map['type']) + }, ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "extra": extra, - "type": type?.toNativeValue(), + "type": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => type?.toNativeValue(), + EnumMethod.value => type?.toValue(), + EnumMethod.name => type?.name() + }, }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_hit_test_result_type.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_hit_test_result_type.g.dart index 477e2b9bf..abfe2fa96 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_hit_test_result_type.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_hit_test_result_type.g.dart @@ -79,20 +79,45 @@ class InAppWebViewHitTestResultType { return null; } + /// Gets a possible [InAppWebViewHitTestResultType] instance value with name [name]. + /// + /// Goes through [InAppWebViewHitTestResultType.values] looking for a value with + /// name [name], as reported by [InAppWebViewHitTestResultType.name]. + /// Returns the first value with the given name, otherwise `null`. + static InAppWebViewHitTestResultType? byName(String? name) { + if (name != null) { + try { + return InAppWebViewHitTestResultType.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [InAppWebViewHitTestResultType] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in InAppWebViewHitTestResultType.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 9: return 'EDIT_TEXT_TYPE'; @@ -113,4 +138,20 @@ class InAppWebViewHitTestResultType { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_initial_data.dart b/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_initial_data.dart index 7a26edb3c..dae877f25 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_initial_data.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_initial_data.dart @@ -1,6 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import '../web_uri.dart'; +import 'enum_method.dart'; part 'in_app_webview_initial_data.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_initial_data.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_initial_data.g.dart index 4cfd6cc9f..b7b5ee91d 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_initial_data.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_initial_data.g.dart @@ -24,7 +24,7 @@ class InAppWebViewInitialData { ///The URL to use as the history entry. If `null` defaults to `about:blank`. If non-null, this must be a valid URL. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView + ///- Android WebView WebUri? historyUrl; ///The MIME type of the data, e.g. "text/html". The default value is `"text/html"`. @@ -41,7 +41,8 @@ class InAppWebViewInitialData { } ///Gets a possible [InAppWebViewInitialData] instance from a [Map] value. - static InAppWebViewInitialData? fromMap(Map? map) { + static InAppWebViewInitialData? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -52,13 +53,17 @@ class InAppWebViewInitialData { data: map['data'], historyUrl: map['historyUrl'] != null ? WebUri(map['historyUrl']) : null, ); - instance.encoding = map['encoding']; - instance.mimeType = map['mimeType']; + if (map['encoding'] != null) { + instance.encoding = map['encoding']; + } + if (map['mimeType'] != null) { + instance.mimeType = map['mimeType']; + } return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "baseUrl": baseUrl?.toString(), "data": data, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_rect.dart b/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_rect.dart index e0c4775b7..f3f3992ad 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_rect.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_rect.dart @@ -1,5 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; +import 'enum_method.dart'; + part 'in_app_webview_rect.g.dart'; ///A class that represents a structure that contains the location and dimensions of a rectangle. diff --git a/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_rect.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_rect.g.dart index fb059d53a..218566fa8 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_rect.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/in_app_webview_rect.g.dart @@ -28,7 +28,8 @@ class InAppWebViewRect { } ///Gets a possible [InAppWebViewRect] instance from a [Map] value. - static InAppWebViewRect? fromMap(Map? map) { + static InAppWebViewRect? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -42,7 +43,7 @@ class InAppWebViewRect { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "height": height, "width": width, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/javascript_handler_callback.dart b/flutter_inappwebview_platform_interface/lib/src/types/javascript_handler_callback.dart index c0a7a7600..8f964e3af 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/javascript_handler_callback.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/javascript_handler_callback.dart @@ -1,15 +1,37 @@ import 'dart:convert'; -import '../in_app_webview/platform_inappwebview_controller.dart'; +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; +import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; + +part 'javascript_handler_callback.g.dart'; + +///Use [JavaScriptHandlerFunction] instead. +@Deprecated('Use JavaScriptHandlerFunction instead') +typedef dynamic JavaScriptHandlerCallback(List arguments); ///This type represents a callback, added with [PlatformInAppWebViewController.addJavaScriptHandler], that listens to post messages sent from JavaScript. /// ///The Android implementation uses [addJavascriptInterface](https://developer.android.com/reference/android/webkit/WebView#addJavascriptInterface(java.lang.Object,%20java.lang.String)). -///The iOS implementation uses [addScriptMessageHandler](https://developer.apple.com/documentation/webkit/wkusercontentcontroller/1537172-addscriptmessagehandler?language=objc) +///The iOS/macOS implementation uses [addScriptMessageHandler](https://developer.apple.com/documentation/webkit/wkusercontentcontroller/1537172-addscriptmessagehandler?language=objc) /// ///The JavaScript function that can be used to call the handler is `window.flutter_inappwebview.callHandler(handlerName , ...args);`, where `args` are [rest parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters). ///The `args` will be stringified automatically using `JSON.stringify(args)` method and then they will be decoded on the Dart side. /// -///Also, a [JavaScriptHandlerCallback] can return json data to the JavaScript side. +///Also, a [JavaScriptHandlerFunction] can return json data to the JavaScript side. ///In this case, simply return data that you want to send and it will be automatically json encoded using [jsonEncode] from the `dart:convert` library. -typedef dynamic JavaScriptHandlerCallback(List arguments); +typedef dynamic JavaScriptHandlerFunction(JavaScriptHandlerFunctionData data); + +///A class that represents the data passed to a [JavaScriptHandlerFunction] added with [PlatformInAppWebViewController.addJavaScriptHandler]. +@ExchangeableObject() +class JavaScriptHandlerFunctionData_ { + List args; + WebUri origin; + bool isMainFrame; + WebUri requestUrl; + + JavaScriptHandlerFunctionData_( + {this.args = const [], + required this.origin, + required this.isMainFrame, + required this.requestUrl}); +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/javascript_handler_callback.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/javascript_handler_callback.g.dart new file mode 100644 index 000000000..253917169 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/javascript_handler_callback.g.dart @@ -0,0 +1,57 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'javascript_handler_callback.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///A class that represents the data passed to a [JavaScriptHandlerFunction] added with [PlatformInAppWebViewController.addJavaScriptHandler]. +class JavaScriptHandlerFunctionData { + List args; + bool isMainFrame; + WebUri origin; + WebUri requestUrl; + JavaScriptHandlerFunctionData( + {this.args = const [], + required this.isMainFrame, + required this.origin, + required this.requestUrl}); + + ///Gets a possible [JavaScriptHandlerFunctionData] instance from a [Map] value. + static JavaScriptHandlerFunctionData? fromMap(Map? map, + {EnumMethod? enumMethod}) { + if (map == null) { + return null; + } + final instance = JavaScriptHandlerFunctionData( + isMainFrame: map['isMainFrame'], + origin: WebUri(map['origin']), + requestUrl: WebUri(map['requestUrl']), + ); + if (map['args'] != null) { + instance.args = List.from(map['args']!.cast()); + } + return instance; + } + + ///Converts instance to a map. + Map toMap({EnumMethod? enumMethod}) { + return { + "args": args, + "isMainFrame": isMainFrame, + "origin": origin.toString(), + "requestUrl": requestUrl.toString(), + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'JavaScriptHandlerFunctionData{args: $args, isMainFrame: $isMainFrame, origin: $origin, requestUrl: $requestUrl}'; + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_alert_request.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_alert_request.dart index 401e7f78b..ad9f66fe9 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_alert_request.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_alert_request.dart @@ -1,6 +1,8 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + import '../in_app_webview/platform_webview.dart'; import '../web_uri.dart'; +import 'enum_method.dart'; part 'js_alert_request.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_alert_request.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_alert_request.g.dart index 9da0d33b3..d907fc39e 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_alert_request.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_alert_request.g.dart @@ -15,8 +15,8 @@ class JsAlertRequest { ///Indicates whether the request was made for the main frame. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS - ///- MacOS + ///- iOS WKWebView + ///- macOS WKWebView bool? isMainFrame; ///Message to be displayed in the window. @@ -33,7 +33,8 @@ class JsAlertRequest { } ///Gets a possible [JsAlertRequest] instance from a [Map] value. - static JsAlertRequest? fromMap(Map? map) { + static JsAlertRequest? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -47,7 +48,7 @@ class JsAlertRequest { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "isMainFrame": isMainFrame, "message": message, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_alert_response.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_alert_response.dart index 1dbc54232..4666c9b07 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_alert_response.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_alert_response.dart @@ -1,6 +1,8 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + import '../in_app_webview/platform_webview.dart'; import 'js_alert_response_action.dart'; +import 'enum_method.dart'; part 'js_alert_response.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_alert_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_alert_response.g.dart index d6903df7c..710c0a0e0 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_alert_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_alert_response.g.dart @@ -26,22 +26,38 @@ class JsAlertResponse { this.message = ""}); ///Gets a possible [JsAlertResponse] instance from a [Map] value. - static JsAlertResponse? fromMap(Map? map) { + static JsAlertResponse? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = JsAlertResponse(); - instance.action = JsAlertResponseAction.fromNativeValue(map['action']); - instance.confirmButtonTitle = map['confirmButtonTitle']; - instance.handledByClient = map['handledByClient']; - instance.message = map['message']; + instance.action = switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + JsAlertResponseAction.fromNativeValue(map['action']), + EnumMethod.value => JsAlertResponseAction.fromValue(map['action']), + EnumMethod.name => JsAlertResponseAction.byName(map['action']) + }; + if (map['confirmButtonTitle'] != null) { + instance.confirmButtonTitle = map['confirmButtonTitle']; + } + if (map['handledByClient'] != null) { + instance.handledByClient = map['handledByClient']; + } + if (map['message'] != null) { + instance.message = map['message']; + } return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "action": action?.toNativeValue(), + "action": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => action?.toNativeValue(), + EnumMethod.value => action?.toValue(), + EnumMethod.name => action?.name() + }, "confirmButtonTitle": confirmButtonTitle, "handledByClient": handledByClient, "message": message, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_alert_response_action.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_alert_response_action.g.dart index 496541321..8327945a3 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_alert_response_action.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_alert_response_action.g.dart @@ -50,24 +50,64 @@ class JsAlertResponseAction { return null; } + /// Gets a possible [JsAlertResponseAction] instance value with name [name]. + /// + /// Goes through [JsAlertResponseAction.values] looking for a value with + /// name [name], as reported by [JsAlertResponseAction.name]. + /// Returns the first value with the given name, otherwise `null`. + static JsAlertResponseAction? byName(String? name) { + if (name != null) { + try { + return JsAlertResponseAction.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [JsAlertResponseAction] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in JsAlertResponseAction.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 0: + return 'CONFIRM'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { - switch (_value) { - case 0: - return 'CONFIRM'; - } - return _value.toString(); + return name(); } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_request.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_request.dart index df75b36f9..cba0144af 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_request.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_request.dart @@ -1,6 +1,8 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + import '../in_app_webview/platform_webview.dart'; import '../web_uri.dart'; +import 'enum_method.dart'; part 'js_before_unload_request.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_request.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_request.g.dart index 0cf1ed4f7..62d70b667 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_request.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_request.g.dart @@ -16,7 +16,8 @@ class JsBeforeUnloadRequest { JsBeforeUnloadRequest({this.message, this.url}); ///Gets a possible [JsBeforeUnloadRequest] instance from a [Map] value. - static JsBeforeUnloadRequest? fromMap(Map? map) { + static JsBeforeUnloadRequest? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -28,7 +29,7 @@ class JsBeforeUnloadRequest { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "message": message, "url": url?.toString(), diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_response.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_response.dart index 0170db589..e2d5bb598 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_response.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_response.dart @@ -1,6 +1,8 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + import '../in_app_webview/platform_webview.dart'; import 'js_before_unload_response_action.dart'; +import 'enum_method.dart'; part 'js_before_unload_response.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_response.g.dart index 885f2f573..40ae46c68 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_response.g.dart @@ -30,24 +30,41 @@ class JsBeforeUnloadResponse { this.message = ""}); ///Gets a possible [JsBeforeUnloadResponse] instance from a [Map] value. - static JsBeforeUnloadResponse? fromMap(Map? map) { + static JsBeforeUnloadResponse? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = JsBeforeUnloadResponse(); - instance.action = - JsBeforeUnloadResponseAction.fromNativeValue(map['action']); - instance.cancelButtonTitle = map['cancelButtonTitle']; - instance.confirmButtonTitle = map['confirmButtonTitle']; - instance.handledByClient = map['handledByClient']; - instance.message = map['message']; + instance.action = switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + JsBeforeUnloadResponseAction.fromNativeValue(map['action']), + EnumMethod.value => JsBeforeUnloadResponseAction.fromValue(map['action']), + EnumMethod.name => JsBeforeUnloadResponseAction.byName(map['action']) + }; + if (map['cancelButtonTitle'] != null) { + instance.cancelButtonTitle = map['cancelButtonTitle']; + } + if (map['confirmButtonTitle'] != null) { + instance.confirmButtonTitle = map['confirmButtonTitle']; + } + if (map['handledByClient'] != null) { + instance.handledByClient = map['handledByClient']; + } + if (map['message'] != null) { + instance.message = map['message']; + } return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "action": action?.toNativeValue(), + "action": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => action?.toNativeValue(), + EnumMethod.value => action?.toValue(), + EnumMethod.name => action?.name() + }, "cancelButtonTitle": cancelButtonTitle, "confirmButtonTitle": confirmButtonTitle, "handledByClient": handledByClient, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_response_action.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_response_action.g.dart index e82005ccb..984769d13 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_response_action.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_before_unload_response_action.g.dart @@ -54,26 +54,67 @@ class JsBeforeUnloadResponseAction { return null; } + /// Gets a possible [JsBeforeUnloadResponseAction] instance value with name [name]. + /// + /// Goes through [JsBeforeUnloadResponseAction.values] looking for a value with + /// name [name], as reported by [JsBeforeUnloadResponseAction.name]. + /// Returns the first value with the given name, otherwise `null`. + static JsBeforeUnloadResponseAction? byName(String? name) { + if (name != null) { + try { + return JsBeforeUnloadResponseAction.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [JsBeforeUnloadResponseAction] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in JsBeforeUnloadResponseAction.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 1: + return 'CANCEL'; + case 0: + return 'CONFIRM'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { - switch (_value) { - case 1: - return 'CANCEL'; - case 0: - return 'CONFIRM'; - } - return _value.toString(); + return name(); } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_request.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_request.dart index efd873029..0e2058389 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_request.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_request.dart @@ -1,6 +1,8 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + import '../in_app_webview/platform_webview.dart'; import '../web_uri.dart'; +import 'enum_method.dart'; part 'js_confirm_request.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_request.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_request.g.dart index 3ab660da2..7d398c110 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_request.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_request.g.dart @@ -15,8 +15,8 @@ class JsConfirmRequest { ///Indicates whether the request was made for the main frame. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS - ///- MacOS + ///- iOS WKWebView + ///- macOS WKWebView bool? isMainFrame; ///Message to be displayed in the window. @@ -33,7 +33,8 @@ class JsConfirmRequest { } ///Gets a possible [JsConfirmRequest] instance from a [Map] value. - static JsConfirmRequest? fromMap(Map? map) { + static JsConfirmRequest? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -47,7 +48,7 @@ class JsConfirmRequest { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "isMainFrame": isMainFrame, "message": message, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_response.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_response.dart index a00083097..3ce0923df 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_response.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_response.dart @@ -1,6 +1,8 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + import '../in_app_webview/platform_webview.dart'; import 'js_confirm_response_action.dart'; +import 'enum_method.dart'; part 'js_confirm_response.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_response.g.dart index ddd0bc9be..f2eb05587 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_response.g.dart @@ -30,23 +30,41 @@ class JsConfirmResponse { this.message = ""}); ///Gets a possible [JsConfirmResponse] instance from a [Map] value. - static JsConfirmResponse? fromMap(Map? map) { + static JsConfirmResponse? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = JsConfirmResponse(); - instance.action = JsConfirmResponseAction.fromNativeValue(map['action']); - instance.cancelButtonTitle = map['cancelButtonTitle']; - instance.confirmButtonTitle = map['confirmButtonTitle']; - instance.handledByClient = map['handledByClient']; - instance.message = map['message']; + instance.action = switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + JsConfirmResponseAction.fromNativeValue(map['action']), + EnumMethod.value => JsConfirmResponseAction.fromValue(map['action']), + EnumMethod.name => JsConfirmResponseAction.byName(map['action']) + }; + if (map['cancelButtonTitle'] != null) { + instance.cancelButtonTitle = map['cancelButtonTitle']; + } + if (map['confirmButtonTitle'] != null) { + instance.confirmButtonTitle = map['confirmButtonTitle']; + } + if (map['handledByClient'] != null) { + instance.handledByClient = map['handledByClient']; + } + if (map['message'] != null) { + instance.message = map['message']; + } return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "action": action?.toNativeValue(), + "action": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => action?.toNativeValue(), + EnumMethod.value => action?.toValue(), + EnumMethod.name => action?.name() + }, "cancelButtonTitle": cancelButtonTitle, "confirmButtonTitle": confirmButtonTitle, "handledByClient": handledByClient, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_response_action.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_response_action.g.dart index a9c706061..be17478a7 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_response_action.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_confirm_response_action.g.dart @@ -54,26 +54,66 @@ class JsConfirmResponseAction { return null; } + /// Gets a possible [JsConfirmResponseAction] instance value with name [name]. + /// + /// Goes through [JsConfirmResponseAction.values] looking for a value with + /// name [name], as reported by [JsConfirmResponseAction.name]. + /// Returns the first value with the given name, otherwise `null`. + static JsConfirmResponseAction? byName(String? name) { + if (name != null) { + try { + return JsConfirmResponseAction.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [JsConfirmResponseAction] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in JsConfirmResponseAction.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 1: + return 'CANCEL'; + case 0: + return 'CONFIRM'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { - switch (_value) { - case 1: - return 'CANCEL'; - case 0: - return 'CONFIRM'; - } - return _value.toString(); + return name(); } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_request.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_request.dart index 87dace2c9..d0e497dbf 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_request.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_request.dart @@ -1,6 +1,8 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + import '../in_app_webview/platform_webview.dart'; import '../web_uri.dart'; +import 'enum_method.dart'; part 'js_prompt_request.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_request.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_request.g.dart index 422d6d179..097b29844 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_request.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_request.g.dart @@ -18,8 +18,8 @@ class JsPromptRequest { ///Indicates whether the request was made for the main frame. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS - ///- MacOS + ///- iOS WKWebView + ///- macOS WKWebView bool? isMainFrame; ///Message to be displayed in the window. @@ -37,7 +37,8 @@ class JsPromptRequest { } ///Gets a possible [JsPromptRequest] instance from a [Map] value. - static JsPromptRequest? fromMap(Map? map) { + static JsPromptRequest? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -52,7 +53,7 @@ class JsPromptRequest { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "defaultValue": defaultValue, "isMainFrame": isMainFrame, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_response.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_response.dart index e262690b7..c3fa4cc32 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_response.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_response.dart @@ -1,6 +1,8 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + import '../in_app_webview/platform_webview.dart'; import 'js_prompt_response_action.dart'; +import 'enum_method.dart'; part 'js_prompt_response.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_response.g.dart index abea1745f..de84d987d 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_response.g.dart @@ -38,26 +38,46 @@ class JsPromptResponse { this.value}); ///Gets a possible [JsPromptResponse] instance from a [Map] value. - static JsPromptResponse? fromMap(Map? map) { + static JsPromptResponse? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = JsPromptResponse( value: map['value'], ); - instance.action = JsPromptResponseAction.fromNativeValue(map['action']); - instance.cancelButtonTitle = map['cancelButtonTitle']; - instance.confirmButtonTitle = map['confirmButtonTitle']; - instance.defaultValue = map['defaultValue']; - instance.handledByClient = map['handledByClient']; - instance.message = map['message']; + instance.action = switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + JsPromptResponseAction.fromNativeValue(map['action']), + EnumMethod.value => JsPromptResponseAction.fromValue(map['action']), + EnumMethod.name => JsPromptResponseAction.byName(map['action']) + }; + if (map['cancelButtonTitle'] != null) { + instance.cancelButtonTitle = map['cancelButtonTitle']; + } + if (map['confirmButtonTitle'] != null) { + instance.confirmButtonTitle = map['confirmButtonTitle']; + } + if (map['defaultValue'] != null) { + instance.defaultValue = map['defaultValue']; + } + if (map['handledByClient'] != null) { + instance.handledByClient = map['handledByClient']; + } + if (map['message'] != null) { + instance.message = map['message']; + } return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "action": action?.toNativeValue(), + "action": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => action?.toNativeValue(), + EnumMethod.value => action?.toValue(), + EnumMethod.name => action?.name() + }, "cancelButtonTitle": cancelButtonTitle, "confirmButtonTitle": confirmButtonTitle, "defaultValue": defaultValue, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_response_action.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_response_action.g.dart index ddebfa6a4..ddd317b9f 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_response_action.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/js_prompt_response_action.g.dart @@ -54,26 +54,66 @@ class JsPromptResponseAction { return null; } + /// Gets a possible [JsPromptResponseAction] instance value with name [name]. + /// + /// Goes through [JsPromptResponseAction.values] looking for a value with + /// name [name], as reported by [JsPromptResponseAction.name]. + /// Returns the first value with the given name, otherwise `null`. + static JsPromptResponseAction? byName(String? name) { + if (name != null) { + try { + return JsPromptResponseAction.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [JsPromptResponseAction] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in JsPromptResponseAction.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 1: + return 'CANCEL'; + case 0: + return 'CONFIRM'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { - switch (_value) { - case 1: - return 'CANCEL'; - case 0: - return 'CONFIRM'; - } - return _value.toString(); + return name(); } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/layout_algorithm.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/layout_algorithm.g.dart index def5e52ad..2f7a6857e 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/layout_algorithm.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/layout_algorithm.g.dart @@ -63,18 +63,65 @@ class LayoutAlgorithm { return null; } + /// Gets a possible [LayoutAlgorithm] instance value with name [name]. + /// + /// Goes through [LayoutAlgorithm.values] looking for a value with + /// name [name], as reported by [LayoutAlgorithm.name]. + /// Returns the first value with the given name, otherwise `null`. + static LayoutAlgorithm? byName(String? name) { + if (name != null) { + try { + return LayoutAlgorithm.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [LayoutAlgorithm] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in LayoutAlgorithm.values) value.name(): value + }; + ///Gets [String] value. String toValue() => _value; ///Gets [String] native value. String toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'NARROW_COLUMNS': + return 'NARROW_COLUMNS'; + case 'NORMAL': + return 'NORMAL'; + case 'TEXT_AUTOSIZING': + return 'TEXT_AUTOSIZING'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { return _value; @@ -140,18 +187,66 @@ class AndroidLayoutAlgorithm { return null; } + /// Gets a possible [AndroidLayoutAlgorithm] instance value with name [name]. + /// + /// Goes through [AndroidLayoutAlgorithm.values] looking for a value with + /// name [name], as reported by [AndroidLayoutAlgorithm.name]. + /// Returns the first value with the given name, otherwise `null`. + static AndroidLayoutAlgorithm? byName(String? name) { + if (name != null) { + try { + return AndroidLayoutAlgorithm.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [AndroidLayoutAlgorithm] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in AndroidLayoutAlgorithm.values) value.name(): value + }; + ///Gets [String] value. String toValue() => _value; ///Gets [String] native value. String toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'NARROW_COLUMNS': + return 'NARROW_COLUMNS'; + case 'NORMAL': + return 'NORMAL'; + case 'TEXT_AUTOSIZING': + return 'TEXT_AUTOSIZING'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { return _value; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/layout_in_display_cutout_mode.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/layout_in_display_cutout_mode.g.dart index 67db5301e..c941ab7f6 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/layout_in_display_cutout_mode.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/layout_in_display_cutout_mode.g.dart @@ -70,20 +70,45 @@ class LayoutInDisplayCutoutMode { return null; } + /// Gets a possible [LayoutInDisplayCutoutMode] instance value with name [name]. + /// + /// Goes through [LayoutInDisplayCutoutMode.values] looking for a value with + /// name [name], as reported by [LayoutInDisplayCutoutMode.name]. + /// Returns the first value with the given name, otherwise `null`. + static LayoutInDisplayCutoutMode? byName(String? name) { + if (name != null) { + try { + return LayoutInDisplayCutoutMode.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [LayoutInDisplayCutoutMode] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in LayoutInDisplayCutoutMode.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 3: return 'ALWAYS'; @@ -96,6 +121,22 @@ class LayoutInDisplayCutoutMode { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } ///Android-specific class representing the share state that should be applied to the custom tab. @@ -168,20 +209,45 @@ class AndroidLayoutInDisplayCutoutMode { return null; } + /// Gets a possible [AndroidLayoutInDisplayCutoutMode] instance value with name [name]. + /// + /// Goes through [AndroidLayoutInDisplayCutoutMode.values] looking for a value with + /// name [name], as reported by [AndroidLayoutInDisplayCutoutMode.name]. + /// Returns the first value with the given name, otherwise `null`. + static AndroidLayoutInDisplayCutoutMode? byName(String? name) { + if (name != null) { + try { + return AndroidLayoutInDisplayCutoutMode.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [AndroidLayoutInDisplayCutoutMode] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in AndroidLayoutInDisplayCutoutMode.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 3: return 'ALWAYS'; @@ -194,4 +260,20 @@ class AndroidLayoutInDisplayCutoutMode { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/loaded_resource.dart b/flutter_inappwebview_platform_interface/lib/src/types/loaded_resource.dart index 0b538034d..21c9aca15 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/loaded_resource.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/loaded_resource.dart @@ -1,6 +1,8 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + import '../in_app_webview/platform_webview.dart'; import '../web_uri.dart'; +import 'enum_method.dart'; part 'loaded_resource.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/loaded_resource.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/loaded_resource.g.dart index 7949c6e57..8993e5adf 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/loaded_resource.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/loaded_resource.g.dart @@ -23,7 +23,8 @@ class LoadedResource { LoadedResource({this.duration, this.initiatorType, this.startTime, this.url}); ///Gets a possible [LoadedResource] instance from a [Map] value. - static LoadedResource? fromMap(Map? map) { + static LoadedResource? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -37,7 +38,7 @@ class LoadedResource { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "duration": duration, "initiatorType": initiatorType, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/login_request.dart b/flutter_inappwebview_platform_interface/lib/src/types/login_request.dart index c68e58756..4f209d3c9 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/login_request.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/login_request.dart @@ -1,5 +1,8 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + import '../in_app_webview/platform_webview.dart'; +import 'enum_method.dart'; + part 'login_request.g.dart'; ///Class used by [PlatformWebViewCreationParams.onReceivedLoginRequest] event. diff --git a/flutter_inappwebview_platform_interface/lib/src/types/login_request.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/login_request.g.dart index 70436ab34..f6e2667ee 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/login_request.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/login_request.g.dart @@ -20,7 +20,8 @@ class LoginRequest { LoginRequest({this.account, required this.args, required this.realm}); ///Gets a possible [LoginRequest] instance from a [Map] value. - static LoginRequest? fromMap(Map? map) { + static LoginRequest? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -33,7 +34,7 @@ class LoginRequest { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "account": account, "args": args, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/main.dart b/flutter_inappwebview_platform_interface/lib/src/types/main.dart index 199ebfb6a..4c4dc9149 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/main.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/main.dart @@ -59,7 +59,11 @@ export 'in_app_webview_hit_test_result_type.dart' show InAppWebViewHitTestResultType; export 'in_app_webview_initial_data.dart' show InAppWebViewInitialData; export 'in_app_webview_rect.dart' show InAppWebViewRect; -export 'javascript_handler_callback.dart' show JavaScriptHandlerCallback; +export 'javascript_handler_callback.dart' + show + JavaScriptHandlerCallback, + JavaScriptHandlerFunction, + JavaScriptHandlerFunctionData; export 'js_alert_request.dart' show JsAlertRequest; export 'js_alert_response.dart' show JsAlertResponse; export 'js_alert_response_action.dart' show JsAlertResponseAction; @@ -225,6 +229,30 @@ export 'tracing_mode.dart' show TracingMode; export 'tracing_category.dart' show TracingCategory; export 'custom_tabs_post_message_result_type.dart' show CustomTabsPostMessageResultType; -export 'custom_scheme_registration.dart' - show CustomSchemeRegistration; +export 'custom_scheme_registration.dart' show CustomSchemeRegistration; export 'disposable.dart'; +export 'frame_kind.dart' show FrameKind; +export 'process_failed_kind.dart' show ProcessFailedKind; +export 'process_failed_reason.dart' show ProcessFailedReason; +export 'process_failed_detail.dart' show ProcessFailedDetail; +export 'focus_direction.dart' show FocusDirection; +export 'enum_method.dart'; +export 'pdf_toolbar_items.dart' show PdfToolbarItems; +export 'webview_interface.dart' show WebViewInterface; +export 'download_start_response_action.dart' show DownloadStartResponseAction; +export 'download_start_response.dart' show DownloadStartResponse; +export 'environment_channel_search_kind.dart' show EnvironmentChannelSearchKind; +export 'environment_release_channels.dart' show EnvironmentReleaseChannels; +export 'environment_scrollbar_style.dart' show EnvironmentScrollbarStyle; +export 'browser_process_exit_kind.dart' show BrowserProcessExitKind; +export 'browser_process_exited_detail.dart' show BrowserProcessExitedDetail; +export 'browser_process_kind.dart' show BrowserProcessKind; +export 'browser_process_info.dart' show BrowserProcessInfo; +export 'browser_process_infos_changed_detail.dart' + show BrowserProcessInfosChangedDetail; +export 'physical_key_status.dart' show PhysicalKeyStatus; +export 'accelerator_key_pressed_detail.dart' show AcceleratorKeyPressedDetail; +export 'proxy_relay_hop.dart' show ProxyRelayHop; +export 'show_file_chooser_request_mode.dart' show ShowFileChooserRequestMode; +export 'show_file_chooser_request.dart' show ShowFileChooserRequest; +export 'show_file_chooser_response.dart' show ShowFileChooserResponse; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/media_capture_state.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/media_capture_state.g.dart index 47a0076ae..0db6b3a76 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/media_capture_state.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/media_capture_state.g.dart @@ -58,20 +58,44 @@ class MediaCaptureState { return null; } + /// Gets a possible [MediaCaptureState] instance value with name [name]. + /// + /// Goes through [MediaCaptureState.values] looking for a value with + /// name [name], as reported by [MediaCaptureState.name]. + /// Returns the first value with the given name, otherwise `null`. + static MediaCaptureState? byName(String? name) { + if (name != null) { + try { + return MediaCaptureState.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [MediaCaptureState] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in MediaCaptureState.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 1: return 'ACTIVE'; @@ -82,4 +106,20 @@ class MediaCaptureState { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/media_playback_state.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/media_playback_state.g.dart index a521269b6..69f6c9267 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/media_playback_state.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/media_playback_state.g.dart @@ -62,20 +62,44 @@ class MediaPlaybackState { return null; } + /// Gets a possible [MediaPlaybackState] instance value with name [name]. + /// + /// Goes through [MediaPlaybackState.values] looking for a value with + /// name [name], as reported by [MediaPlaybackState.name]. + /// Returns the first value with the given name, otherwise `null`. + static MediaPlaybackState? byName(String? name) { + if (name != null) { + try { + return MediaPlaybackState.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [MediaPlaybackState] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in MediaPlaybackState.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 0: return 'NONE'; @@ -88,4 +112,20 @@ class MediaPlaybackState { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/meta_tag.dart b/flutter_inappwebview_platform_interface/lib/src/types/meta_tag.dart index 892e4688a..0d22a6604 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/meta_tag.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/meta_tag.dart @@ -2,6 +2,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_i import '../in_app_webview/platform_inappwebview_controller.dart'; import 'meta_tag_attribute.dart'; +import 'enum_method.dart'; part 'meta_tag.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/meta_tag.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/meta_tag.g.dart index cbbd3505d..95029ab0d 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/meta_tag.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/meta_tag.g.dart @@ -19,14 +19,15 @@ class MetaTag { MetaTag({this.attrs, this.content, this.name}); ///Gets a possible [MetaTag] instance from a [Map] value. - static MetaTag? fromMap(Map? map) { + static MetaTag? fromMap(Map? map, {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = MetaTag( attrs: map['attrs'] != null - ? List.from(map['attrs'].map( - (e) => MetaTagAttribute.fromMap(e?.cast())!)) + ? List.from(map['attrs'].map((e) => + MetaTagAttribute.fromMap(e?.cast(), + enumMethod: enumMethod)!)) : null, content: map['content'], name: map['name'], @@ -35,9 +36,9 @@ class MetaTag { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "attrs": attrs?.map((e) => e.toMap()).toList(), + "attrs": attrs?.map((e) => e.toMap(enumMethod: enumMethod)).toList(), "content": content, "name": name, }; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/meta_tag_attribute.dart b/flutter_inappwebview_platform_interface/lib/src/types/meta_tag_attribute.dart index 35048ed18..ba25c70c6 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/meta_tag_attribute.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/meta_tag_attribute.dart @@ -1,6 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import 'meta_tag.dart'; +import 'enum_method.dart'; part 'meta_tag_attribute.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/meta_tag_attribute.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/meta_tag_attribute.g.dart index 8e546a065..cd663bf8e 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/meta_tag_attribute.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/meta_tag_attribute.g.dart @@ -16,7 +16,8 @@ class MetaTagAttribute { MetaTagAttribute({this.name, this.value}); ///Gets a possible [MetaTagAttribute] instance from a [Map] value. - static MetaTagAttribute? fromMap(Map? map) { + static MetaTagAttribute? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -28,7 +29,7 @@ class MetaTagAttribute { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "name": name, "value": value, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/mixed_content_mode.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/mixed_content_mode.g.dart index 23cdf1436..ba7f4dbe2 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/mixed_content_mode.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/mixed_content_mode.g.dart @@ -65,20 +65,44 @@ class MixedContentMode { return null; } + /// Gets a possible [MixedContentMode] instance value with name [name]. + /// + /// Goes through [MixedContentMode.values] looking for a value with + /// name [name], as reported by [MixedContentMode.name]. + /// Returns the first value with the given name, otherwise `null`. + static MixedContentMode? byName(String? name) { + if (name != null) { + try { + return MixedContentMode.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [MixedContentMode] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in MixedContentMode.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 0: return 'MIXED_CONTENT_ALWAYS_ALLOW'; @@ -89,6 +113,22 @@ class MixedContentMode { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } ///An Android-specific class used to configure the WebView's behavior when a secure origin attempts to load a resource from an insecure origin. @@ -157,20 +197,44 @@ class AndroidMixedContentMode { return null; } + /// Gets a possible [AndroidMixedContentMode] instance value with name [name]. + /// + /// Goes through [AndroidMixedContentMode.values] looking for a value with + /// name [name], as reported by [AndroidMixedContentMode.name]. + /// Returns the first value with the given name, otherwise `null`. + static AndroidMixedContentMode? byName(String? name) { + if (name != null) { + try { + return AndroidMixedContentMode.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [AndroidMixedContentMode] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in AndroidMixedContentMode.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 0: return 'MIXED_CONTENT_ALWAYS_ALLOW'; @@ -181,4 +245,20 @@ class AndroidMixedContentMode { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/modal_presentation_style.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/modal_presentation_style.g.dart index 71ca9419e..3786dbdf9 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/modal_presentation_style.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/modal_presentation_style.g.dart @@ -88,20 +88,44 @@ class ModalPresentationStyle { return null; } + /// Gets a possible [ModalPresentationStyle] instance value with name [name]. + /// + /// Goes through [ModalPresentationStyle.values] looking for a value with + /// name [name], as reported by [ModalPresentationStyle.name]. + /// Returns the first value with the given name, otherwise `null`. + static ModalPresentationStyle? byName(String? name) { + if (name != null) { + try { + return ModalPresentationStyle.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [ModalPresentationStyle] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in ModalPresentationStyle.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 9: return 'AUTOMATIC'; @@ -126,6 +150,22 @@ class ModalPresentationStyle { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } ///An iOS-specific class used to specify the modal presentation style when presenting a view controller. @@ -213,20 +253,45 @@ class IOSUIModalPresentationStyle { return null; } + /// Gets a possible [IOSUIModalPresentationStyle] instance value with name [name]. + /// + /// Goes through [IOSUIModalPresentationStyle.values] looking for a value with + /// name [name], as reported by [IOSUIModalPresentationStyle.name]. + /// Returns the first value with the given name, otherwise `null`. + static IOSUIModalPresentationStyle? byName(String? name) { + if (name != null) { + try { + return IOSUIModalPresentationStyle.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [IOSUIModalPresentationStyle] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in IOSUIModalPresentationStyle.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 9: return 'AUTOMATIC'; @@ -251,4 +316,20 @@ class IOSUIModalPresentationStyle { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/modal_transition_style.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/modal_transition_style.g.dart index a5cd6ff7c..9816e993e 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/modal_transition_style.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/modal_transition_style.g.dart @@ -68,20 +68,44 @@ class ModalTransitionStyle { return null; } + /// Gets a possible [ModalTransitionStyle] instance value with name [name]. + /// + /// Goes through [ModalTransitionStyle.values] looking for a value with + /// name [name], as reported by [ModalTransitionStyle.name]. + /// Returns the first value with the given name, otherwise `null`. + static ModalTransitionStyle? byName(String? name) { + if (name != null) { + try { + return ModalTransitionStyle.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [ModalTransitionStyle] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in ModalTransitionStyle.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 0: return 'COVER_VERTICAL'; @@ -94,6 +118,22 @@ class ModalTransitionStyle { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } ///An iOS-specific class used to specify the transition style when presenting a view controller. @@ -160,20 +200,45 @@ class IOSUIModalTransitionStyle { return null; } + /// Gets a possible [IOSUIModalTransitionStyle] instance value with name [name]. + /// + /// Goes through [IOSUIModalTransitionStyle.values] looking for a value with + /// name [name], as reported by [IOSUIModalTransitionStyle.name]. + /// Returns the first value with the given name, otherwise `null`. + static IOSUIModalTransitionStyle? byName(String? name) { + if (name != null) { + try { + return IOSUIModalTransitionStyle.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [IOSUIModalTransitionStyle] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in IOSUIModalTransitionStyle.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 0: return 'COVER_VERTICAL'; @@ -186,4 +251,20 @@ class IOSUIModalTransitionStyle { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/navigation_action.dart b/flutter_inappwebview_platform_interface/lib/src/types/navigation_action.dart index cdae14782..01bad8270 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/navigation_action.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/navigation_action.dart @@ -3,6 +3,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_i import 'url_request.dart'; import 'navigation_type.dart'; import 'frame_info.dart'; +import 'enum_method.dart'; part 'navigation_action.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/navigation_action.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/navigation_action.g.dart index 59b5169c4..6588434a8 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/navigation_action.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/navigation_action.g.dart @@ -21,13 +21,11 @@ class NavigationAction { ///the sequence of events which caused the request to be created was initiated by a user ///gesture. /// - ///**NOTE for Android native WebView**: On Android < 21, this is always `false` - /// - ///**NOTE for Windows**: Available only if the request is associated to the [PlatformWebViewCreationParams.onCreateWindow] event - /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView 21+ ([Official API - WebResourceRequest.hasGesture](https://developer.android.com/reference/android/webkit/WebResourceRequest#hasGesture())) - ///- Windows + ///- Android WebView 21+ ([Official API - WebResourceRequest.hasGesture](https://developer.android.com/reference/android/webkit/WebResourceRequest#hasGesture())): + /// - On Android < 21, this is always `false` + ///- Windows WebView2: + /// - Available only if the request is associated to the [PlatformWebViewCreationParams.onCreateWindow] event bool? hasGesture; ///Use [sourceFrame] instead. @@ -54,16 +52,16 @@ class NavigationAction { ///Also, on Android < 21, this is always `false`. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView 21+ ([Official API - WebResourceRequest.isRedirect](https://developer.android.com/reference/android/webkit/WebResourceRequest#isRedirect())) - ///- Windows + ///- Android WebView 21+ ([Official API - WebResourceRequest.isRedirect](https://developer.android.com/reference/android/webkit/WebResourceRequest#isRedirect())) + ///- Windows WebView2 bool? isRedirect; ///The type of action triggering the navigation. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - WKNavigationAction.navigationType](https://developer.apple.com/documentation/webkit/wknavigationaction/1401914-navigationtype)) - ///- MacOS ([Official API - WKNavigationAction.navigationType](https://developer.apple.com/documentation/webkit/wknavigationaction/1401914-navigationtype)) - ///- Windows + ///- iOS WKWebView ([Official API - WKNavigationAction.navigationType](https://developer.apple.com/documentation/webkit/wknavigationaction/1401914-navigationtype)) + ///- macOS WKWebView ([Official API - WKNavigationAction.navigationType](https://developer.apple.com/documentation/webkit/wknavigationaction/1401914-navigationtype)) + ///- Windows WebView2 NavigationType? navigationType; ///The URL request object associated with the navigation action. @@ -77,22 +75,22 @@ class NavigationAction { ///A value indicating whether the web content used a download attribute to indicate that this should be downloaded. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS 14.5+ ([Official API - WKNavigationAction.shouldPerformDownload](https://developer.apple.com/documentation/webkit/wknavigationaction/3727357-shouldperformdownload)) - ///- MacOS 11.3+ ([Official API - WKNavigationAction.shouldPerformDownload](https://developer.apple.com/documentation/webkit/wknavigationaction/3727357-shouldperformdownload)) + ///- iOS WKWebView 14.5+ ([Official API - WKNavigationAction.shouldPerformDownload](https://developer.apple.com/documentation/webkit/wknavigationaction/3727357-shouldperformdownload)) + ///- macOS WKWebView 11.3+ ([Official API - WKNavigationAction.shouldPerformDownload](https://developer.apple.com/documentation/webkit/wknavigationaction/3727357-shouldperformdownload)) bool? shouldPerformDownload; ///The frame that requested the navigation. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - WKNavigationAction.sourceFrame](https://developer.apple.com/documentation/webkit/wknavigationaction/1401926-sourceframe)) - ///- MacOS ([Official API - WKNavigationAction.sourceFrame](https://developer.apple.com/documentation/webkit/wknavigationaction/1401926-sourceframe)) + ///- iOS WKWebView ([Official API - WKNavigationAction.sourceFrame](https://developer.apple.com/documentation/webkit/wknavigationaction/1401926-sourceframe)) + ///- macOS WKWebView ([Official API - WKNavigationAction.sourceFrame](https://developer.apple.com/documentation/webkit/wknavigationaction/1401926-sourceframe)) FrameInfo? sourceFrame; ///The frame in which to display the new content. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - WKNavigationAction.targetFrame](https://developer.apple.com/documentation/webkit/wknavigationaction/1401918-targetframe)) - ///- MacOS ([Official API - WKNavigationAction.targetFrame](https://developer.apple.com/documentation/webkit/wknavigationaction/1401918-targetframe)) + ///- iOS WKWebView ([Official API - WKNavigationAction.targetFrame](https://developer.apple.com/documentation/webkit/wknavigationaction/1401918-targetframe)) + ///- macOS WKWebView ([Official API - WKNavigationAction.targetFrame](https://developer.apple.com/documentation/webkit/wknavigationaction/1401918-targetframe)) FrameInfo? targetFrame; NavigationAction( {@Deprecated('Use hasGesture instead') this.androidHasGesture, @@ -117,7 +115,8 @@ class NavigationAction { } ///Gets a possible [NavigationAction] instance from a [Map] value. - static NavigationAction? fromMap(Map? map) { + static NavigationAction? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -125,36 +124,55 @@ class NavigationAction { androidHasGesture: map['hasGesture'], androidIsRedirect: map['isRedirect'], hasGesture: map['hasGesture'], - iosSourceFrame: - IOSWKFrameInfo.fromMap(map['sourceFrame']?.cast()), - iosTargetFrame: - IOSWKFrameInfo.fromMap(map['targetFrame']?.cast()), - iosWKNavigationType: + iosSourceFrame: IOSWKFrameInfo.fromMap( + map['sourceFrame']?.cast(), + enumMethod: enumMethod), + iosTargetFrame: IOSWKFrameInfo.fromMap( + map['targetFrame']?.cast(), + enumMethod: enumMethod), + iosWKNavigationType: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => IOSWKNavigationType.fromNativeValue(map['navigationType']), + EnumMethod.value => + IOSWKNavigationType.fromValue(map['navigationType']), + EnumMethod.name => IOSWKNavigationType.byName(map['navigationType']) + }, isForMainFrame: map['isForMainFrame'], isRedirect: map['isRedirect'], - navigationType: NavigationType.fromNativeValue(map['navigationType']), - request: URLRequest.fromMap(map['request']?.cast())!, + navigationType: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + NavigationType.fromNativeValue(map['navigationType']), + EnumMethod.value => NavigationType.fromValue(map['navigationType']), + EnumMethod.name => NavigationType.byName(map['navigationType']) + }, + request: URLRequest.fromMap(map['request']?.cast(), + enumMethod: enumMethod)!, shouldPerformDownload: map['shouldPerformDownload'], - sourceFrame: - FrameInfo.fromMap(map['sourceFrame']?.cast()), - targetFrame: - FrameInfo.fromMap(map['targetFrame']?.cast()), + sourceFrame: FrameInfo.fromMap( + map['sourceFrame']?.cast(), + enumMethod: enumMethod), + targetFrame: FrameInfo.fromMap( + map['targetFrame']?.cast(), + enumMethod: enumMethod), ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "hasGesture": hasGesture, "isForMainFrame": isForMainFrame, "isRedirect": isRedirect, - "navigationType": navigationType?.toNativeValue(), - "request": request.toMap(), + "navigationType": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => navigationType?.toNativeValue(), + EnumMethod.value => navigationType?.toValue(), + EnumMethod.name => navigationType?.name() + }, + "request": request.toMap(enumMethod: enumMethod), "shouldPerformDownload": shouldPerformDownload, - "sourceFrame": sourceFrame?.toMap(), - "targetFrame": targetFrame?.toMap(), + "sourceFrame": sourceFrame?.toMap(enumMethod: enumMethod), + "targetFrame": targetFrame?.toMap(enumMethod: enumMethod), }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/navigation_action_policy.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/navigation_action_policy.g.dart index 5bca8ddfb..464d56e40 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/navigation_action_policy.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/navigation_action_policy.g.dart @@ -61,20 +61,44 @@ class NavigationActionPolicy { return null; } + /// Gets a possible [NavigationActionPolicy] instance value with name [name]. + /// + /// Goes through [NavigationActionPolicy.values] looking for a value with + /// name [name], as reported by [NavigationActionPolicy.name]. + /// Returns the first value with the given name, otherwise `null`. + static NavigationActionPolicy? byName(String? name) { + if (name != null) { + try { + return NavigationActionPolicy.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [NavigationActionPolicy] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in NavigationActionPolicy.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 1: return 'ALLOW'; @@ -85,4 +109,20 @@ class NavigationActionPolicy { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/navigation_response.dart b/flutter_inappwebview_platform_interface/lib/src/types/navigation_response.dart index 0caee8019..19a99f76d 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/navigation_response.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/navigation_response.dart @@ -1,6 +1,8 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + import '../in_app_webview/platform_webview.dart'; import 'url_response.dart'; +import 'enum_method.dart'; part 'navigation_response.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/navigation_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/navigation_response.g.dart index 14f5e74a8..12ef553ed 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/navigation_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/navigation_response.g.dart @@ -22,24 +22,26 @@ class NavigationResponse { this.response}); ///Gets a possible [NavigationResponse] instance from a [Map] value. - static NavigationResponse? fromMap(Map? map) { + static NavigationResponse? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = NavigationResponse( canShowMIMEType: map['canShowMIMEType'], isForMainFrame: map['isForMainFrame'], - response: URLResponse.fromMap(map['response']?.cast()), + response: URLResponse.fromMap(map['response']?.cast(), + enumMethod: enumMethod), ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "canShowMIMEType": canShowMIMEType, "isForMainFrame": isForMainFrame, - "response": response?.toMap(), + "response": response?.toMap(enumMethod: enumMethod), }; } @@ -72,25 +74,26 @@ class IOSWKNavigationResponse { this.response}); ///Gets a possible [IOSWKNavigationResponse] instance from a [Map] value. - static IOSWKNavigationResponse? fromMap(Map? map) { + static IOSWKNavigationResponse? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = IOSWKNavigationResponse( canShowMIMEType: map['canShowMIMEType'], isForMainFrame: map['isForMainFrame'], - response: - IOSURLResponse.fromMap(map['response']?.cast()), + response: IOSURLResponse.fromMap(map['response']?.cast(), + enumMethod: enumMethod), ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "canShowMIMEType": canShowMIMEType, "isForMainFrame": isForMainFrame, - "response": response?.toMap(), + "response": response?.toMap(enumMethod: enumMethod), }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/navigation_response_action.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/navigation_response_action.g.dart index 6c361637d..088811d79 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/navigation_response_action.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/navigation_response_action.g.dart @@ -61,20 +61,44 @@ class NavigationResponseAction { return null; } + /// Gets a possible [NavigationResponseAction] instance value with name [name]. + /// + /// Goes through [NavigationResponseAction.values] looking for a value with + /// name [name], as reported by [NavigationResponseAction.name]. + /// Returns the first value with the given name, otherwise `null`. + static NavigationResponseAction? byName(String? name) { + if (name != null) { + try { + return NavigationResponseAction.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [NavigationResponseAction] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in NavigationResponseAction.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 1: return 'ALLOW'; @@ -85,6 +109,22 @@ class NavigationResponseAction { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } ///Class that is used by [PlatformWebViewCreationParams.onNavigationResponse] event. @@ -138,26 +178,67 @@ class IOSNavigationResponseAction { return null; } + /// Gets a possible [IOSNavigationResponseAction] instance value with name [name]. + /// + /// Goes through [IOSNavigationResponseAction.values] looking for a value with + /// name [name], as reported by [IOSNavigationResponseAction.name]. + /// Returns the first value with the given name, otherwise `null`. + static IOSNavigationResponseAction? byName(String? name) { + if (name != null) { + try { + return IOSNavigationResponseAction.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [IOSNavigationResponseAction] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in IOSNavigationResponseAction.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 1: + return 'ALLOW'; + case 0: + return 'CANCEL'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { - switch (_value) { - case 1: - return 'ALLOW'; - case 0: - return 'CANCEL'; - } - return _value.toString(); + return name(); } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/navigation_type.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/navigation_type.g.dart index 7615cd66f..665d9a5c5 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/navigation_type.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/navigation_type.g.dart @@ -19,9 +19,9 @@ class NavigationType { ///An item from the back-forward list was requested. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - WKNavigationType.formSubmitted](https://developer.apple.com/documentation/webkit/wknavigationtype/formsubmitted)) - ///- MacOS ([Official API - WKNavigationType.formSubmitted](https://developer.apple.com/documentation/webkit/wknavigationtype/formsubmitted)) - ///- Windows ([Official API - COREWEBVIEW2_NAVIGATION_KIND_BACK_OR_FORWARD](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_navigation_kind)) + ///- iOS WKWebView ([Official API - WKNavigationType.formSubmitted](https://developer.apple.com/documentation/webkit/wknavigationtype/formsubmitted)) + ///- macOS WKWebView ([Official API - WKNavigationType.formSubmitted](https://developer.apple.com/documentation/webkit/wknavigationtype/formsubmitted)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_NAVIGATION_KIND_BACK_OR_FORWARD](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_navigation_kind)) static final BACK_FORWARD = NavigationType._internalMultiPlatform('BACK_FORWARD', () { switch (defaultTargetPlatform) { @@ -40,8 +40,8 @@ class NavigationType { ///A form was resubmitted (for example by going back, going forward, or reloading). /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - WKNavigationType.formSubmitted](https://developer.apple.com/documentation/webkit/wknavigationtype/formresubmitted)) - ///- MacOS ([Official API - WKNavigationType.formSubmitted](https://developer.apple.com/documentation/webkit/wknavigationtype/formresubmitted)) + ///- iOS WKWebView ([Official API - WKNavigationType.formSubmitted](https://developer.apple.com/documentation/webkit/wknavigationtype/formresubmitted)) + ///- macOS WKWebView ([Official API - WKNavigationType.formSubmitted](https://developer.apple.com/documentation/webkit/wknavigationtype/formresubmitted)) static final FORM_RESUBMITTED = NavigationType._internalMultiPlatform('FORM_RESUBMITTED', () { switch (defaultTargetPlatform) { @@ -58,8 +58,8 @@ class NavigationType { ///A form was submitted. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - WKNavigationType.formSubmitted](https://developer.apple.com/documentation/webkit/wknavigationtype/formsubmitted)) - ///- MacOS ([Official API - WKNavigationType.formSubmitted](https://developer.apple.com/documentation/webkit/wknavigationtype/formsubmitted)) + ///- iOS WKWebView ([Official API - WKNavigationType.formSubmitted](https://developer.apple.com/documentation/webkit/wknavigationtype/formsubmitted)) + ///- macOS WKWebView ([Official API - WKNavigationType.formSubmitted](https://developer.apple.com/documentation/webkit/wknavigationtype/formsubmitted)) static final FORM_SUBMITTED = NavigationType._internalMultiPlatform('FORM_SUBMITTED', () { switch (defaultTargetPlatform) { @@ -76,9 +76,9 @@ class NavigationType { ///A link with an href attribute was activated by the user. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - WKNavigationType.linkActivated](https://developer.apple.com/documentation/webkit/wknavigationtype/linkactivated)) - ///- MacOS ([Official API - WKNavigationType.linkActivated](https://developer.apple.com/documentation/webkit/wknavigationtype/linkactivated)) - ///- Windows + ///- iOS WKWebView ([Official API - WKNavigationType.linkActivated](https://developer.apple.com/documentation/webkit/wknavigationtype/linkactivated)) + ///- macOS WKWebView ([Official API - WKNavigationType.linkActivated](https://developer.apple.com/documentation/webkit/wknavigationtype/linkactivated)) + ///- Windows WebView2 static final LINK_ACTIVATED = NavigationType._internalMultiPlatform('LINK_ACTIVATED', () { switch (defaultTargetPlatform) { @@ -97,9 +97,9 @@ class NavigationType { ///Navigation is taking place for some other reason. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - WKNavigationType.other](https://developer.apple.com/documentation/webkit/wknavigationtype/other)) - ///- MacOS ([Official API - WKNavigationType.other](https://developer.apple.com/documentation/webkit/wknavigationtype/other)) - ///- Windows + ///- iOS WKWebView ([Official API - WKNavigationType.other](https://developer.apple.com/documentation/webkit/wknavigationtype/other)) + ///- macOS WKWebView ([Official API - WKNavigationType.other](https://developer.apple.com/documentation/webkit/wknavigationtype/other)) + ///- Windows WebView2 static final OTHER = NavigationType._internalMultiPlatform('OTHER', () { switch (defaultTargetPlatform) { case TargetPlatform.iOS: @@ -117,9 +117,9 @@ class NavigationType { ///The webpage was reloaded. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - WKNavigationType.reload](https://developer.apple.com/documentation/webkit/wknavigationtype/reload)) - ///- MacOS ([Official API - WKNavigationType.reload](https://developer.apple.com/documentation/webkit/wknavigationtype/reload)) - ///- Windows ([Official API - COREWEBVIEW2_NAVIGATION_KIND_RELOAD](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_navigation_kind)) + ///- iOS WKWebView ([Official API - WKNavigationType.reload](https://developer.apple.com/documentation/webkit/wknavigationtype/reload)) + ///- macOS WKWebView ([Official API - WKNavigationType.reload](https://developer.apple.com/documentation/webkit/wknavigationtype/reload)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_NAVIGATION_KIND_RELOAD](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_navigation_kind)) static final RELOAD = NavigationType._internalMultiPlatform('RELOAD', () { switch (defaultTargetPlatform) { case TargetPlatform.iOS: @@ -170,18 +170,71 @@ class NavigationType { return null; } + /// Gets a possible [NavigationType] instance value with name [name]. + /// + /// Goes through [NavigationType.values] looking for a value with + /// name [name], as reported by [NavigationType.name]. + /// Returns the first value with the given name, otherwise `null`. + static NavigationType? byName(String? name) { + if (name != null) { + try { + return NavigationType.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [NavigationType] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in NavigationType.values) value.name(): value + }; + ///Gets [String] value. String toValue() => _value; - ///Gets [int?] native value. + ///Gets [int] native value if supported by the current platform, otherwise `null`. int? toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'BACK_FORWARD': + return 'BACK_FORWARD'; + case 'FORM_RESUBMITTED': + return 'FORM_RESUBMITTED'; + case 'FORM_SUBMITTED': + return 'FORM_SUBMITTED'; + case 'LINK_ACTIVATED': + return 'LINK_ACTIVATED'; + case 'OTHER': + return 'OTHER'; + case 'RELOAD': + return 'RELOAD'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + @override String toString() { return _value; @@ -254,20 +307,44 @@ class IOSWKNavigationType { return null; } + /// Gets a possible [IOSWKNavigationType] instance value with name [name]. + /// + /// Goes through [IOSWKNavigationType.values] looking for a value with + /// name [name], as reported by [IOSWKNavigationType.name]. + /// Returns the first value with the given name, otherwise `null`. + static IOSWKNavigationType? byName(String? name) { + if (name != null) { + try { + return IOSWKNavigationType.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [IOSWKNavigationType] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in IOSWKNavigationType.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 2: return 'BACK_FORWARD'; @@ -284,4 +361,20 @@ class IOSWKNavigationType { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/over_scroll_mode.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/over_scroll_mode.g.dart index 7e4b5e432..ca887ad7a 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/over_scroll_mode.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/over_scroll_mode.g.dart @@ -59,20 +59,43 @@ class OverScrollMode { return null; } + /// Gets a possible [OverScrollMode] instance value with name [name]. + /// + /// Goes through [OverScrollMode.values] looking for a value with + /// name [name], as reported by [OverScrollMode.name]. + /// Returns the first value with the given name, otherwise `null`. + static OverScrollMode? byName(String? name) { + if (name != null) { + try { + return OverScrollMode.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [OverScrollMode] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in OverScrollMode.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 0: return 'ALWAYS'; @@ -83,6 +106,22 @@ class OverScrollMode { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } ///An Android-specific class used to configure the `WebView`'s over-scroll mode. @@ -141,20 +180,44 @@ class AndroidOverScrollMode { return null; } + /// Gets a possible [AndroidOverScrollMode] instance value with name [name]. + /// + /// Goes through [AndroidOverScrollMode.values] looking for a value with + /// name [name], as reported by [AndroidOverScrollMode.name]. + /// Returns the first value with the given name, otherwise `null`. + static AndroidOverScrollMode? byName(String? name) { + if (name != null) { + try { + return AndroidOverScrollMode.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [AndroidOverScrollMode] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in AndroidOverScrollMode.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 0: return 'OVER_SCROLL_ALWAYS'; @@ -165,4 +228,20 @@ class AndroidOverScrollMode { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/pdf_configuration.dart b/flutter_inappwebview_platform_interface/lib/src/types/pdf_configuration.dart index 20e52f937..e807960ec 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/pdf_configuration.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/pdf_configuration.dart @@ -1,6 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import 'in_app_webview_rect.dart'; +import 'enum_method.dart'; part 'pdf_configuration.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/pdf_configuration.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/pdf_configuration.g.dart index b4c069453..ed54234d3 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/pdf_configuration.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/pdf_configuration.g.dart @@ -15,20 +15,22 @@ class PDFConfiguration { PDFConfiguration({this.rect}); ///Gets a possible [PDFConfiguration] instance from a [Map] value. - static PDFConfiguration? fromMap(Map? map) { + static PDFConfiguration? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = PDFConfiguration( - rect: InAppWebViewRect.fromMap(map['rect']?.cast()), + rect: InAppWebViewRect.fromMap(map['rect']?.cast(), + enumMethod: enumMethod), ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "rect": rect?.toMap(), + "rect": rect?.toMap(enumMethod: enumMethod), }; } @@ -57,20 +59,22 @@ class IOSWKPDFConfiguration { IOSWKPDFConfiguration({this.rect}); ///Gets a possible [IOSWKPDFConfiguration] instance from a [Map] value. - static IOSWKPDFConfiguration? fromMap(Map? map) { + static IOSWKPDFConfiguration? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = IOSWKPDFConfiguration( - rect: InAppWebViewRect.fromMap(map['rect']?.cast()), + rect: InAppWebViewRect.fromMap(map['rect']?.cast(), + enumMethod: enumMethod), ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "rect": rect?.toMap(), + "rect": rect?.toMap(enumMethod: enumMethod), }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/pdf_toolbar_items.dart b/flutter_inappwebview_platform_interface/lib/src/types/pdf_toolbar_items.dart new file mode 100644 index 000000000..c6f346e4e --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/pdf_toolbar_items.dart @@ -0,0 +1,53 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +part 'pdf_toolbar_items.g.dart'; + +///Class used to customize the PDF toolbar items. +@ExchangeableEnum(bitwiseOrOperator: true) +class PdfToolbarItems_ { + // ignore: unused_field + final int _value; + const PdfToolbarItems_._internal(this._value); + + ///No item. + static const NONE = const PdfToolbarItems_._internal(0); + + ///The save button. + static const SAVE = const PdfToolbarItems_._internal(1); + + ///The print button. + static const PRINT = const PdfToolbarItems_._internal(2); + + ///The save as button. + static const SAVE_AS = const PdfToolbarItems_._internal(4); + + ///The zoom in button. + static const ZOOM_IN = const PdfToolbarItems_._internal(8); + + ///The zoom out button. + static const ZOOM_OUT = const PdfToolbarItems_._internal(16); + + ///The rotate button. + static const ROTATE = const PdfToolbarItems_._internal(32); + + ///The fit page button. + static const FIT_PAGE = const PdfToolbarItems_._internal(64); + + ///The page layout button. + static const PAGE_LAYOUT = const PdfToolbarItems_._internal(128); + + ///The bookmarks button. + static const BOOKMARKS = const PdfToolbarItems_._internal(256); + + ///The page select button. + static const PAGE_SELECTOR = const PdfToolbarItems_._internal(512); + + ///The search button. + static const SEARCH = const PdfToolbarItems_._internal(1024); + + ///The full screen button. + static const FULL_SCREEN = const PdfToolbarItems_._internal(2048); + + ///The more settings button. + static const MORE_SETTINGS = const PdfToolbarItems_._internal(4096); +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/pdf_toolbar_items.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/pdf_toolbar_items.g.dart new file mode 100644 index 000000000..a40929eb0 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/pdf_toolbar_items.g.dart @@ -0,0 +1,194 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'pdf_toolbar_items.dart'; + +// ************************************************************************** +// ExchangeableEnumGenerator +// ************************************************************************** + +///Class used to customize the PDF toolbar items. +class PdfToolbarItems { + final int _value; + final int _nativeValue; + const PdfToolbarItems._internal(this._value, this._nativeValue); +// ignore: unused_element + factory PdfToolbarItems._internalMultiPlatform( + int value, Function nativeValue) => + PdfToolbarItems._internal(value, nativeValue()); + + ///The bookmarks button. + static const BOOKMARKS = PdfToolbarItems._internal(256, 256); + + ///The fit page button. + static const FIT_PAGE = PdfToolbarItems._internal(64, 64); + + ///The full screen button. + static const FULL_SCREEN = PdfToolbarItems._internal(2048, 2048); + + ///The more settings button. + static const MORE_SETTINGS = PdfToolbarItems._internal(4096, 4096); + + ///No item. + static const NONE = PdfToolbarItems._internal(0, 0); + + ///The page layout button. + static const PAGE_LAYOUT = PdfToolbarItems._internal(128, 128); + + ///The page select button. + static const PAGE_SELECTOR = PdfToolbarItems._internal(512, 512); + + ///The print button. + static const PRINT = PdfToolbarItems._internal(2, 2); + + ///The rotate button. + static const ROTATE = PdfToolbarItems._internal(32, 32); + + ///The save button. + static const SAVE = PdfToolbarItems._internal(1, 1); + + ///The save as button. + static const SAVE_AS = PdfToolbarItems._internal(4, 4); + + ///The search button. + static const SEARCH = PdfToolbarItems._internal(1024, 1024); + + ///The zoom in button. + static const ZOOM_IN = PdfToolbarItems._internal(8, 8); + + ///The zoom out button. + static const ZOOM_OUT = PdfToolbarItems._internal(16, 16); + + ///Set of all values of [PdfToolbarItems]. + static final Set values = [ + PdfToolbarItems.BOOKMARKS, + PdfToolbarItems.FIT_PAGE, + PdfToolbarItems.FULL_SCREEN, + PdfToolbarItems.MORE_SETTINGS, + PdfToolbarItems.NONE, + PdfToolbarItems.PAGE_LAYOUT, + PdfToolbarItems.PAGE_SELECTOR, + PdfToolbarItems.PRINT, + PdfToolbarItems.ROTATE, + PdfToolbarItems.SAVE, + PdfToolbarItems.SAVE_AS, + PdfToolbarItems.SEARCH, + PdfToolbarItems.ZOOM_IN, + PdfToolbarItems.ZOOM_OUT, + ].toSet(); + + ///Gets a possible [PdfToolbarItems] instance from [int] value. + static PdfToolbarItems? fromValue(int? value) { + if (value != null) { + try { + return PdfToolbarItems.values + .firstWhere((element) => element.toValue() == value); + } catch (e) { + return PdfToolbarItems._internal(value, value); + } + } + return null; + } + + ///Gets a possible [PdfToolbarItems] instance from a native value. + static PdfToolbarItems? fromNativeValue(int? value) { + if (value != null) { + try { + return PdfToolbarItems.values + .firstWhere((element) => element.toNativeValue() == value); + } catch (e) { + return PdfToolbarItems._internal(value, value); + } + } + return null; + } + + /// Gets a possible [PdfToolbarItems] instance value with name [name]. + /// + /// Goes through [PdfToolbarItems.values] looking for a value with + /// name [name], as reported by [PdfToolbarItems.name]. + /// Returns the first value with the given name, otherwise `null`. + static PdfToolbarItems? byName(String? name) { + if (name != null) { + try { + return PdfToolbarItems.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [PdfToolbarItems] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in PdfToolbarItems.values) value.name(): value + }; + + ///Gets [int] value. + int toValue() => _value; + + ///Gets [int] native value. + int toNativeValue() => _nativeValue; + + ///Gets the name of the value. + String name() { + switch (_value) { + case 256: + return 'BOOKMARKS'; + case 64: + return 'FIT_PAGE'; + case 2048: + return 'FULL_SCREEN'; + case 4096: + return 'MORE_SETTINGS'; + case 0: + return 'NONE'; + case 128: + return 'PAGE_LAYOUT'; + case 512: + return 'PAGE_SELECTOR'; + case 2: + return 'PRINT'; + case 32: + return 'ROTATE'; + case 1: + return 'SAVE'; + case 4: + return 'SAVE_AS'; + case 1024: + return 'SEARCH'; + case 8: + return 'ZOOM_IN'; + case 16: + return 'ZOOM_OUT'; + } + return _value.toString(); + } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + PdfToolbarItems operator |(PdfToolbarItems value) => + PdfToolbarItems._internal( + value.toValue() | _value, value.toNativeValue() | _nativeValue); + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/permission_request.dart b/flutter_inappwebview_platform_interface/lib/src/types/permission_request.dart index e5588ef76..dc0ca59cf 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/permission_request.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/permission_request.dart @@ -1,9 +1,11 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + import '../in_app_webview/platform_webview.dart'; import '../web_uri.dart'; import 'permission_resource_type.dart'; import 'permission_response.dart'; import 'frame_info.dart'; +import 'enum_method.dart'; part 'permission_request.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/permission_request.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/permission_request.g.dart index a52ea4d80..d2061f1c2 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/permission_request.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/permission_request.g.dart @@ -23,25 +23,40 @@ class PermissionRequest { {this.frame, required this.origin, this.resources = const []}); ///Gets a possible [PermissionRequest] instance from a [Map] value. - static PermissionRequest? fromMap(Map? map) { + static PermissionRequest? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = PermissionRequest( - frame: FrameInfo.fromMap(map['frame']?.cast()), + frame: FrameInfo.fromMap(map['frame']?.cast(), + enumMethod: enumMethod), origin: WebUri(map['origin']), ); - instance.resources = List.from(map['resources'] - .map((e) => PermissionResourceType.fromNativeValue(e)!)); + if (map['resources'] != null) { + instance.resources = List.from(map['resources'] + .map((e) => switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + PermissionResourceType.fromNativeValue(e), + EnumMethod.value => PermissionResourceType.fromValue(e), + EnumMethod.name => PermissionResourceType.byName(e) + }!)); + } return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "frame": frame?.toMap(), + "frame": frame?.toMap(enumMethod: enumMethod), "origin": origin.toString(), - "resources": resources.map((e) => e.toNativeValue()).toList(), + "resources": resources + .map((e) => switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => e.toNativeValue(), + EnumMethod.value => e.toValue(), + EnumMethod.name => e.name() + }) + .toList(), }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/permission_resource_type.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/permission_resource_type.g.dart index 80b482269..94f9d6405 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/permission_resource_type.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/permission_resource_type.g.dart @@ -23,7 +23,7 @@ class PermissionResourceType { ///for details. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - COREWEBVIEW2_PERMISSION_KIND_AUTOPLAY](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PERMISSION_KIND_AUTOPLAY](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) static final AUTOPLAY = PermissionResourceType._internalMultiPlatform('AUTOPLAY', () { switch (defaultTargetPlatform) { @@ -38,10 +38,10 @@ class PermissionResourceType { ///Resource belongs to video capture device, like camera. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - PermissionRequest.RESOURCE_VIDEO_CAPTURE](https://developer.android.com/reference/android/webkit/PermissionRequest#RESOURCE_VIDEO_CAPTURE)) - ///- iOS 15.0+ ([Official API - WKMediaCaptureType.camera](https://developer.apple.com/documentation/webkit/wkmediacapturetype/camera)) - ///- MacOS 12.0+ ([Official API - WKMediaCaptureType.camera](https://developer.apple.com/documentation/webkit/wkmediacapturetype/camera)) - ///- Windows ([Official API - COREWEBVIEW2_PERMISSION_KIND_CAMERA](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) + ///- Android WebView ([Official API - PermissionRequest.RESOURCE_VIDEO_CAPTURE](https://developer.android.com/reference/android/webkit/PermissionRequest#RESOURCE_VIDEO_CAPTURE)) + ///- iOS WKWebView 15.0+ ([Official API - WKMediaCaptureType.camera](https://developer.apple.com/documentation/webkit/wkmediacapturetype/camera)) + ///- macOS WKWebView 12.0+ ([Official API - WKMediaCaptureType.camera](https://developer.apple.com/documentation/webkit/wkmediacapturetype/camera)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PERMISSION_KIND_CAMERA](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) static final CAMERA = PermissionResourceType._internalMultiPlatform('CAMERA', () { switch (defaultTargetPlatform) { @@ -62,8 +62,8 @@ class PermissionResourceType { ///A media device or devices that can capture audio and video. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS 15.0+ ([Official API - WKMediaCaptureType.cameraAndMicrophone](https://developer.apple.com/documentation/webkit/wkmediacapturetype/cameraandmicrophone)) - ///- MacOS 12.0+ ([Official API - WKMediaCaptureType.cameraAndMicrophone](https://developer.apple.com/documentation/webkit/wkmediacapturetype/cameraandmicrophone)) + ///- iOS WKWebView 15.0+ ([Official API - WKMediaCaptureType.cameraAndMicrophone](https://developer.apple.com/documentation/webkit/wkmediacapturetype/cameraandmicrophone)) + ///- macOS WKWebView 12.0+ ([Official API - WKMediaCaptureType.cameraAndMicrophone](https://developer.apple.com/documentation/webkit/wkmediacapturetype/cameraandmicrophone)) static final CAMERA_AND_MICROPHONE = PermissionResourceType._internalMultiPlatform('CAMERA_AND_MICROPHONE', () { @@ -81,7 +81,7 @@ class PermissionResourceType { ///Indicates permission to read the system clipboard without a user gesture. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - COREWEBVIEW2_PERMISSION_KIND_CLIPBOARD_READ](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PERMISSION_KIND_CLIPBOARD_READ](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) static final CLIPBOARD_READ = PermissionResourceType._internalMultiPlatform('CLIPBOARD_READ', () { switch (defaultTargetPlatform) { @@ -96,8 +96,8 @@ class PermissionResourceType { ///Resource belongs to the device’s orientation and motion. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS 15.0+ - ///- MacOS 12.0+ + ///- iOS WKWebView 15.0+ + ///- macOS WKWebView 12.0+ static final DEVICE_ORIENTATION_AND_MOTION = PermissionResourceType._internalMultiPlatform( 'DEVICE_ORIENTATION_AND_MOTION', () { @@ -118,7 +118,7 @@ class PermissionResourceType { ///"readwrite" permission for the user's selection. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - COREWEBVIEW2_PERMISSION_KIND_FILE_READ_WRITE](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PERMISSION_KIND_FILE_READ_WRITE](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) static final FILE_READ_WRITE = PermissionResourceType._internalMultiPlatform('FILE_READ_WRITE', () { switch (defaultTargetPlatform) { @@ -133,7 +133,7 @@ class PermissionResourceType { ///Indicates permission to access geolocation. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - COREWEBVIEW2_PERMISSION_KIND_GEOLOCATION](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PERMISSION_KIND_GEOLOCATION](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) static final GEOLOCATION = PermissionResourceType._internalMultiPlatform('GEOLOCATION', () { switch (defaultTargetPlatform) { @@ -150,7 +150,7 @@ class PermissionResourceType { ///to query the system fonts available for styling web content. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - COREWEBVIEW2_PERMISSION_KIND_LOCAL_FONTS](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PERMISSION_KIND_LOCAL_FONTS](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) static final LOCAL_FONTS = PermissionResourceType._internalMultiPlatform('LOCAL_FONTS', () { switch (defaultTargetPlatform) { @@ -165,10 +165,10 @@ class PermissionResourceType { ///Resource belongs to audio capture device, like microphone. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - PermissionRequest.RESOURCE_AUDIO_CAPTURE](https://developer.android.com/reference/android/webkit/PermissionRequest#RESOURCE_AUDIO_CAPTURE)) - ///- iOS 15.0+ ([Official API - WKMediaCaptureType.microphone](https://developer.apple.com/documentation/webkit/wkmediacapturetype/microphone)) - ///- MacOS 12.0+ ([Official API - WKMediaCaptureType.microphone](https://developer.apple.com/documentation/webkit/wkmediacapturetype/microphone)) - ///- Windows ([Official API - COREWEBVIEW2_PERMISSION_KIND_MICROPHONE](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) + ///- Android WebView ([Official API - PermissionRequest.RESOURCE_AUDIO_CAPTURE](https://developer.android.com/reference/android/webkit/PermissionRequest#RESOURCE_AUDIO_CAPTURE)) + ///- iOS WKWebView 15.0+ ([Official API - WKMediaCaptureType.microphone](https://developer.apple.com/documentation/webkit/wkmediacapturetype/microphone)) + ///- macOS WKWebView 12.0+ ([Official API - WKMediaCaptureType.microphone](https://developer.apple.com/documentation/webkit/wkmediacapturetype/microphone)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PERMISSION_KIND_MICROPHONE](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) static final MICROPHONE = PermissionResourceType._internalMultiPlatform('MICROPHONE', () { switch (defaultTargetPlatform) { @@ -191,8 +191,8 @@ class PermissionResourceType { ///Permission may be requested for this resource in API levels 21 and above, if the Android device has been updated to WebView 45 or above. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - PermissionRequest.RESOURCE_MIDI_SYSEX](https://developer.android.com/reference/android/webkit/PermissionRequest#RESOURCE_MIDI_SYSEX)) - ///- Windows ([Official API - COREWEBVIEW2_PERMISSION_KIND_MIDI_SYSTEM_EXCLUSIVE_MESSAGES](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) + ///- Android WebView ([Official API - PermissionRequest.RESOURCE_MIDI_SYSEX](https://developer.android.com/reference/android/webkit/PermissionRequest#RESOURCE_MIDI_SYSEX)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PERMISSION_KIND_MIDI_SYSTEM_EXCLUSIVE_MESSAGES](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) static final MIDI_SYSEX = PermissionResourceType._internalMultiPlatform('MIDI_SYSEX', () { switch (defaultTargetPlatform) { @@ -210,7 +210,7 @@ class PermissionResourceType { ///Permission is requested when multiple downloads are triggered in quick succession. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - COREWEBVIEW2_PERMISSION_KIND_MULTIPLE_AUTOMATIC_DOWNLOADS](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PERMISSION_KIND_MULTIPLE_AUTOMATIC_DOWNLOADS](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) static final MULTIPLE_AUTOMATIC_DOWNLOADS = PermissionResourceType._internalMultiPlatform( 'MULTIPLE_AUTOMATIC_DOWNLOADS', () { @@ -226,7 +226,7 @@ class PermissionResourceType { ///Indicates permission to send web notifications. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - COREWEBVIEW2_PERMISSION_KIND_NOTIFICATIONS](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PERMISSION_KIND_NOTIFICATIONS](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) static final NOTIFICATIONS = PermissionResourceType._internalMultiPlatform('NOTIFICATIONS', () { switch (defaultTargetPlatform) { @@ -241,7 +241,7 @@ class PermissionResourceType { ///Indicates permission to access generic sensor. Generic Sensor covers ambient-light-sensor, accelerometer, gyroscope, and magnetometer. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - COREWEBVIEW2_PERMISSION_KIND_OTHER_SENSORS](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PERMISSION_KIND_OTHER_SENSORS](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) static final OTHER_SENSORS = PermissionResourceType._internalMultiPlatform('OTHER_SENSORS', () { switch (defaultTargetPlatform) { @@ -256,7 +256,7 @@ class PermissionResourceType { ///Resource belongs to protected media identifier. After the user grants this resource, the origin can use EME APIs to generate the license requests. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID](https://developer.android.com/reference/android/webkit/PermissionRequest#RESOURCE_PROTECTED_MEDIA_ID)) + ///- Android WebView ([Official API - PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID](https://developer.android.com/reference/android/webkit/PermissionRequest#RESOURCE_PROTECTED_MEDIA_ID)) static final PROTECTED_MEDIA_ID = PermissionResourceType._internalMultiPlatform('PROTECTED_MEDIA_ID', () { switch (defaultTargetPlatform) { @@ -271,7 +271,7 @@ class PermissionResourceType { ///Indicates an unknown permission. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - COREWEBVIEW2_PERMISSION_KIND_UNKNOWN_PERMISSION](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PERMISSION_KIND_UNKNOWN_PERMISSION](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) static final UNKNOWN = PermissionResourceType._internalMultiPlatform('UNKNOWN', () { switch (defaultTargetPlatform) { @@ -288,7 +288,7 @@ class PermissionResourceType { ///to get screen details. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - COREWEBVIEW2_PERMISSION_KIND_WINDOW_MANAGEMENT](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PERMISSION_KIND_WINDOW_MANAGEMENT](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2792.45#corewebview2_permission_kind)) static final WINDOW_MANAGEMENT = PermissionResourceType._internalMultiPlatform('WINDOW_MANAGEMENT', () { switch (defaultTargetPlatform) { @@ -346,18 +346,92 @@ class PermissionResourceType { return null; } + /// Gets a possible [PermissionResourceType] instance value with name [name]. + /// + /// Goes through [PermissionResourceType.values] looking for a value with + /// name [name], as reported by [PermissionResourceType.name]. + /// Returns the first value with the given name, otherwise `null`. + static PermissionResourceType? byName(String? name) { + if (name != null) { + try { + return PermissionResourceType.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [PermissionResourceType] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in PermissionResourceType.values) value.name(): value + }; + ///Gets [String] value. String toValue() => _value; - ///Gets [dynamic] native value. + ///Gets [dynamic] native value if supported by the current platform, otherwise `null`. dynamic toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'AUTOPLAY': + return 'AUTOPLAY'; + case 'CAMERA': + return 'CAMERA'; + case 'CAMERA_AND_MICROPHONE': + return 'CAMERA_AND_MICROPHONE'; + case 'CLIPBOARD_READ': + return 'CLIPBOARD_READ'; + case 'DEVICE_ORIENTATION_AND_MOTION': + return 'DEVICE_ORIENTATION_AND_MOTION'; + case 'FILE_READ_WRITE': + return 'FILE_READ_WRITE'; + case 'GEOLOCATION': + return 'GEOLOCATION'; + case 'LOCAL_FONTS': + return 'LOCAL_FONTS'; + case 'MICROPHONE': + return 'MICROPHONE'; + case 'MIDI_SYSEX': + return 'MIDI_SYSEX'; + case 'MULTIPLE_AUTOMATIC_DOWNLOADS': + return 'MULTIPLE_AUTOMATIC_DOWNLOADS'; + case 'NOTIFICATIONS': + return 'NOTIFICATIONS'; + case 'OTHER_SENSORS': + return 'OTHER_SENSORS'; + case 'PROTECTED_MEDIA_ID': + return 'PROTECTED_MEDIA_ID'; + case 'UNKNOWN': + return 'UNKNOWN'; + case 'WINDOW_MANAGEMENT': + return 'WINDOW_MANAGEMENT'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + @override String toString() { return _value; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/permission_response.dart b/flutter_inappwebview_platform_interface/lib/src/types/permission_response.dart index 453b80063..39b7d6457 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/permission_response.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/permission_response.dart @@ -1,7 +1,9 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + import '../in_app_webview/platform_webview.dart'; import 'permission_resource_type.dart'; import 'permission_response_action.dart'; +import 'enum_method.dart'; part 'permission_response.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/permission_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/permission_response.g.dart index 1cd597f28..296ae8548 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/permission_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/permission_response.g.dart @@ -19,22 +19,45 @@ class PermissionResponse { {this.action = PermissionResponseAction.DENY, this.resources = const []}); ///Gets a possible [PermissionResponse] instance from a [Map] value. - static PermissionResponse? fromMap(Map? map) { + static PermissionResponse? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = PermissionResponse(); - instance.action = PermissionResponseAction.fromNativeValue(map['action']); - instance.resources = List.from(map['resources'] - .map((e) => PermissionResourceType.fromNativeValue(e)!)); + instance.action = switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + PermissionResponseAction.fromNativeValue(map['action']), + EnumMethod.value => PermissionResponseAction.fromValue(map['action']), + EnumMethod.name => PermissionResponseAction.byName(map['action']) + }; + if (map['resources'] != null) { + instance.resources = List.from(map['resources'] + .map((e) => switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + PermissionResourceType.fromNativeValue(e), + EnumMethod.value => PermissionResourceType.fromValue(e), + EnumMethod.name => PermissionResourceType.byName(e) + }!)); + } return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "action": action?.toNativeValue(), - "resources": resources.map((e) => e.toNativeValue()).toList(), + "action": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => action?.toNativeValue(), + EnumMethod.value => action?.toValue(), + EnumMethod.name => action?.name() + }, + "resources": resources + .map((e) => switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => e.toNativeValue(), + EnumMethod.value => e.toValue(), + EnumMethod.name => e.name() + }) + .toList(), }; } @@ -63,21 +86,33 @@ class PermissionRequestResponse { this.resources = const []}); ///Gets a possible [PermissionRequestResponse] instance from a [Map] value. - static PermissionRequestResponse? fromMap(Map? map) { + static PermissionRequestResponse? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = PermissionRequestResponse(); - instance.action = - PermissionRequestResponseAction.fromNativeValue(map['action']); - instance.resources = List.from(map['resources']!.cast()); + instance.action = switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + PermissionRequestResponseAction.fromNativeValue(map['action']), + EnumMethod.value => + PermissionRequestResponseAction.fromValue(map['action']), + EnumMethod.name => PermissionRequestResponseAction.byName(map['action']) + }; + if (map['resources'] != null) { + instance.resources = List.from(map['resources']!.cast()); + } return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "action": action?.toNativeValue(), + "action": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => action?.toNativeValue(), + EnumMethod.value => action?.toValue(), + EnumMethod.name => action?.name() + }, "resources": resources, }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/permission_response_action.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/permission_response_action.g.dart index 33c5e4964..1e4e85295 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/permission_response_action.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/permission_response_action.g.dart @@ -58,20 +58,44 @@ class PermissionResponseAction { return null; } + /// Gets a possible [PermissionResponseAction] instance value with name [name]. + /// + /// Goes through [PermissionResponseAction.values] looking for a value with + /// name [name], as reported by [PermissionResponseAction.name]. + /// Returns the first value with the given name, otherwise `null`. + static PermissionResponseAction? byName(String? name) { + if (name != null) { + try { + return PermissionResponseAction.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [PermissionResponseAction] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in PermissionResponseAction.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 0: return 'DENY'; @@ -82,6 +106,22 @@ class PermissionResponseAction { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } ///Class used by [PermissionRequestResponse] class. @@ -135,26 +175,67 @@ class PermissionRequestResponseAction { return null; } + /// Gets a possible [PermissionRequestResponseAction] instance value with name [name]. + /// + /// Goes through [PermissionRequestResponseAction.values] looking for a value with + /// name [name], as reported by [PermissionRequestResponseAction.name]. + /// Returns the first value with the given name, otherwise `null`. + static PermissionRequestResponseAction? byName(String? name) { + if (name != null) { + try { + return PermissionRequestResponseAction.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [PermissionRequestResponseAction] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in PermissionRequestResponseAction.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 0: + return 'DENY'; + case 1: + return 'GRANT'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { - switch (_value) { - case 0: - return 'DENY'; - case 1: - return 'GRANT'; - } - return _value.toString(); + return name(); } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/physical_key_status.dart b/flutter_inappwebview_platform_interface/lib/src/types/physical_key_status.dart new file mode 100644 index 000000000..4177c4ab0 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/physical_key_status.dart @@ -0,0 +1,37 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +import 'enum_method.dart'; + +part 'physical_key_status.g.dart'; + +///Contains the information packed into the LPARAM sent to a Win32 key event. +@ExchangeableObject() +class PhysicalKeyStatus_ { + ///Indicates that the key is an extended key. + bool isExtendedKey; + + ///Indicates that the key was released. + bool isKeyReleased; + + ///Indicates that a menu key is held down (context code). + bool isMenuKeyDown; + + ///Specifies the repeat count for the current message. + int repeatCount; + + ///Specifies the scan code. + int scanCode; + + ///Indicates that the key was held down. + bool wasKeyDown; + + @ExchangeableObjectConstructor() + PhysicalKeyStatus_({ + required this.isExtendedKey, + required this.isKeyReleased, + required this.isMenuKeyDown, + required this.repeatCount, + required this.scanCode, + required this.wasKeyDown, + }); +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/physical_key_status.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/physical_key_status.g.dart new file mode 100644 index 000000000..a655c26e0 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/physical_key_status.g.dart @@ -0,0 +1,74 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'physical_key_status.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///Contains the information packed into the LPARAM sent to a Win32 key event. +class PhysicalKeyStatus { + ///Indicates that the key is an extended key. + bool isExtendedKey; + + ///Indicates that the key was released. + bool isKeyReleased; + + ///Indicates that a menu key is held down (context code). + bool isMenuKeyDown; + + ///Specifies the repeat count for the current message. + int repeatCount; + + ///Specifies the scan code. + int scanCode; + + ///Indicates that the key was held down. + bool wasKeyDown; + PhysicalKeyStatus( + {required this.isExtendedKey, + required this.isKeyReleased, + required this.isMenuKeyDown, + required this.repeatCount, + required this.scanCode, + required this.wasKeyDown}); + + ///Gets a possible [PhysicalKeyStatus] instance from a [Map] value. + static PhysicalKeyStatus? fromMap(Map? map, + {EnumMethod? enumMethod}) { + if (map == null) { + return null; + } + final instance = PhysicalKeyStatus( + isExtendedKey: map['isExtendedKey'], + isKeyReleased: map['isKeyReleased'], + isMenuKeyDown: map['isMenuKeyDown'], + repeatCount: map['repeatCount'], + scanCode: map['scanCode'], + wasKeyDown: map['wasKeyDown'], + ); + return instance; + } + + ///Converts instance to a map. + Map toMap({EnumMethod? enumMethod}) { + return { + "isExtendedKey": isExtendedKey, + "isKeyReleased": isKeyReleased, + "isMenuKeyDown": isMenuKeyDown, + "repeatCount": repeatCount, + "scanCode": scanCode, + "wasKeyDown": wasKeyDown, + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'PhysicalKeyStatus{isExtendedKey: $isExtendedKey, isKeyReleased: $isKeyReleased, isMenuKeyDown: $isMenuKeyDown, repeatCount: $repeatCount, scanCode: $scanCode, wasKeyDown: $wasKeyDown}'; + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/prewarming_token.dart b/flutter_inappwebview_platform_interface/lib/src/types/prewarming_token.dart index 583ba2b94..cc460b81c 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/prewarming_token.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/prewarming_token.dart @@ -1,6 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import '../chrome_safari_browser/platform_chrome_safari_browser.dart'; +import 'enum_method.dart'; part 'prewarming_token.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/prewarming_token.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/prewarming_token.g.dart index 334482b8b..bec21040d 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/prewarming_token.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/prewarming_token.g.dart @@ -13,7 +13,8 @@ class PrewarmingToken { PrewarmingToken({required this.id}); ///Gets a possible [PrewarmingToken] instance from a [Map] value. - static PrewarmingToken? fromMap(Map? map) { + static PrewarmingToken? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -24,7 +25,7 @@ class PrewarmingToken { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "id": id, }; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/print_job_attributes.dart b/flutter_inappwebview_platform_interface/lib/src/types/print_job_attributes.dart index db5c09244..c108314e1 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/print_job_attributes.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/print_job_attributes.dart @@ -1,17 +1,18 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; -import '../util.dart'; import '../print_job/main.dart'; +import '../util.dart'; import '../web_uri.dart'; +import 'enum_method.dart'; import 'in_app_webview_rect.dart'; import 'print_job_color_mode.dart'; +import 'print_job_disposition.dart'; import 'print_job_duplex_mode.dart'; -import 'print_job_orientation.dart'; import 'print_job_media_size.dart'; -import 'print_job_resolution.dart'; +import 'print_job_orientation.dart'; import 'print_job_pagination_mode.dart'; -import 'print_job_disposition.dart'; +import 'print_job_resolution.dart'; part 'print_job_attributes.g.dart'; @@ -32,6 +33,11 @@ class PrintJobAttributes_ { PrintJobDuplexMode_? duplex; ///The orientation of the printed content, portrait or landscape. + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + ]) PrintJobOrientation_? orientation; ///The media size. diff --git a/flutter_inappwebview_platform_interface/lib/src/types/print_job_attributes.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/print_job_attributes.g.dart index 6c9a99cf3..118128585 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/print_job_attributes.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/print_job_attributes.g.dart @@ -12,28 +12,28 @@ class PrintJobAttributes { ///The color mode. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- MacOS + ///- Android WebView + ///- macOS WKWebView PrintJobColorMode? colorMode; ///If `true`, produce detailed reports when an error occurs. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView bool? detailedErrorReporting; ///The duplex mode to use for the print job. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView 23+ - ///- iOS - ///- MacOS + ///- Android WebView 23+ + ///- iOS WKWebView + ///- macOS WKWebView PrintJobDuplexMode? duplex; ///A fax number. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView String? faxNumber; ///The height of the page footer. @@ -42,13 +42,13 @@ class PrintJobAttributes { ///The default footer height is `0.0`. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS + ///- iOS WKWebView double? footerHeight; ///If `true`, a standard header and footer are added outside the margins of each page. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView bool? headerAndFooter; ///The height of the page header. @@ -57,49 +57,49 @@ class PrintJobAttributes { ///The default header height is `0.0`. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS + ///- iOS WKWebView double? headerHeight; ///The horizontal pagination mode. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView PrintJobPaginationMode? horizontalPagination; ///Indicates whether the image is centered horizontally. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView bool? isHorizontallyCentered; ///Indicates whether only the currently selected contents should be printed. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView bool? isSelectionOnly; ///Indicates whether the image is centered vertically. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView bool? isVerticallyCentered; ///The action specified for the job. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView PrintJobDisposition? jobDisposition; ///An URL containing the location to which the job file will be saved when the [jobDisposition] is [PrintJobDisposition.SAVE]. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView WebUri? jobSavingURL; ///The human-readable name of the currently selected paper size, suitable for presentation in user interfaces. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView String? localizedPaperName; ///The margins for each printed page. @@ -107,8 +107,8 @@ class PrintJobAttributes { ///the amount of white space on the left of the content and so on. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS - ///- MacOS + ///- iOS WKWebView + ///- macOS WKWebView EdgeInsets? margins; ///The maximum height of the content area. @@ -119,7 +119,7 @@ class PrintJobAttributes { ///The default value of this property is the maximum float value. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS + ///- iOS WKWebView double? maximumContentHeight; ///The maximum width of the content area. @@ -129,40 +129,45 @@ class PrintJobAttributes { ///The default value of this property is the maximum float value. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS + ///- iOS WKWebView double? maximumContentWidth; ///The media size. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView + ///- Android WebView PrintJobMediaSize? mediaSize; ///If `true`, collates output. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView bool? mustCollate; ///The orientation of the printed content, portrait or landscape. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView PrintJobOrientation? orientation; ///The number of logical pages to be tiled horizontally on a physical sheet of paper. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView int? pagesAcross; ///The number of logical pages to be tiled vertically on a physical sheet of paper. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView int? pagesDown; ///The name of the currently selected paper size. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView String? paperName; ///The size of the paper used for printing. @@ -171,8 +176,8 @@ class PrintJobAttributes { ///The origin is always (0,0). /// ///**Officially Supported Platforms/Implementations**: - ///- iOS - ///- MacOS + ///- iOS WKWebView + ///- macOS WKWebView InAppWebViewRect? paperRect; ///The area in which printing can occur. @@ -181,32 +186,32 @@ class PrintJobAttributes { ///Sometimes this is referred to as the imageable area of the paper. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS - ///- MacOS + ///- iOS WKWebView + ///- macOS WKWebView InAppWebViewRect? printableRect; ///The supported resolution in DPI (dots per inch). /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView + ///- Android WebView PrintJobResolution? resolution; ///The current scaling factor. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView double? scalingFactor; ///A timestamp that specifies the time at which printing should begin. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView int? time; ///The vertical pagination to the specified mode. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView PrintJobPaginationMode? verticalPagination; PrintJobAttributes( {this.colorMode, @@ -240,84 +245,145 @@ class PrintJobAttributes { this.verticalPagination}); ///Gets a possible [PrintJobAttributes] instance from a [Map] value. - static PrintJobAttributes? fromMap(Map? map) { + static PrintJobAttributes? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = PrintJobAttributes( - colorMode: PrintJobColorMode.fromNativeValue(map['colorMode']), + colorMode: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + PrintJobColorMode.fromNativeValue(map['colorMode']), + EnumMethod.value => PrintJobColorMode.fromValue(map['colorMode']), + EnumMethod.name => PrintJobColorMode.byName(map['colorMode']) + }, detailedErrorReporting: map['detailedErrorReporting'], - duplex: PrintJobDuplexMode.fromNativeValue(map['duplex']), + duplex: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + PrintJobDuplexMode.fromNativeValue(map['duplex']), + EnumMethod.value => PrintJobDuplexMode.fromValue(map['duplex']), + EnumMethod.name => PrintJobDuplexMode.byName(map['duplex']) + }, faxNumber: map['faxNumber'], footerHeight: map['footerHeight'], headerAndFooter: map['headerAndFooter'], headerHeight: map['headerHeight'], - horizontalPagination: + horizontalPagination: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => PrintJobPaginationMode.fromNativeValue(map['horizontalPagination']), + EnumMethod.value => + PrintJobPaginationMode.fromValue(map['horizontalPagination']), + EnumMethod.name => + PrintJobPaginationMode.byName(map['horizontalPagination']) + }, isHorizontallyCentered: map['isHorizontallyCentered'], isSelectionOnly: map['isSelectionOnly'], isVerticallyCentered: map['isVerticallyCentered'], - jobDisposition: + jobDisposition: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => PrintJobDisposition.fromNativeValue(map['jobDisposition']), + EnumMethod.value => + PrintJobDisposition.fromValue(map['jobDisposition']), + EnumMethod.name => PrintJobDisposition.byName(map['jobDisposition']) + }, jobSavingURL: map['jobSavingURL'] != null ? WebUri(map['jobSavingURL']) : null, localizedPaperName: map['localizedPaperName'], margins: MapEdgeInsets.fromMap(map['margins']?.cast()), maximumContentHeight: map['maximumContentHeight'], maximumContentWidth: map['maximumContentWidth'], - mediaSize: - PrintJobMediaSize.fromMap(map['mediaSize']?.cast()), + mediaSize: PrintJobMediaSize.fromMap( + map['mediaSize']?.cast(), + enumMethod: enumMethod), mustCollate: map['mustCollate'], - orientation: PrintJobOrientation.fromNativeValue(map['orientation']), + orientation: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + PrintJobOrientation.fromNativeValue(map['orientation']), + EnumMethod.value => PrintJobOrientation.fromValue(map['orientation']), + EnumMethod.name => PrintJobOrientation.byName(map['orientation']) + }, pagesAcross: map['pagesAcross'], pagesDown: map['pagesDown'], paperName: map['paperName'], - paperRect: - InAppWebViewRect.fromMap(map['paperRect']?.cast()), + paperRect: InAppWebViewRect.fromMap( + map['paperRect']?.cast(), + enumMethod: enumMethod), printableRect: InAppWebViewRect.fromMap( - map['printableRect']?.cast()), + map['printableRect']?.cast(), + enumMethod: enumMethod), resolution: PrintJobResolution.fromMap( - map['resolution']?.cast()), + map['resolution']?.cast(), + enumMethod: enumMethod), scalingFactor: map['scalingFactor'], time: map['time'], - verticalPagination: + verticalPagination: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => PrintJobPaginationMode.fromNativeValue(map['verticalPagination']), + EnumMethod.value => + PrintJobPaginationMode.fromValue(map['verticalPagination']), + EnumMethod.name => + PrintJobPaginationMode.byName(map['verticalPagination']) + }, ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "colorMode": colorMode?.toNativeValue(), + "colorMode": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => colorMode?.toNativeValue(), + EnumMethod.value => colorMode?.toValue(), + EnumMethod.name => colorMode?.name() + }, "detailedErrorReporting": detailedErrorReporting, - "duplex": duplex?.toNativeValue(), + "duplex": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => duplex?.toNativeValue(), + EnumMethod.value => duplex?.toValue(), + EnumMethod.name => duplex?.name() + }, "faxNumber": faxNumber, "footerHeight": footerHeight, "headerAndFooter": headerAndFooter, "headerHeight": headerHeight, - "horizontalPagination": horizontalPagination?.toNativeValue(), + "horizontalPagination": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => horizontalPagination?.toNativeValue(), + EnumMethod.value => horizontalPagination?.toValue(), + EnumMethod.name => horizontalPagination?.name() + }, "isHorizontallyCentered": isHorizontallyCentered, "isSelectionOnly": isSelectionOnly, "isVerticallyCentered": isVerticallyCentered, - "jobDisposition": jobDisposition?.toNativeValue(), + "jobDisposition": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => jobDisposition?.toNativeValue(), + EnumMethod.value => jobDisposition?.toValue(), + EnumMethod.name => jobDisposition?.name() + }, "jobSavingURL": jobSavingURL?.toString(), "localizedPaperName": localizedPaperName, "margins": margins?.toMap(), "maximumContentHeight": maximumContentHeight, "maximumContentWidth": maximumContentWidth, - "mediaSize": mediaSize?.toMap(), + "mediaSize": mediaSize?.toMap(enumMethod: enumMethod), "mustCollate": mustCollate, - "orientation": orientation?.toNativeValue(), + "orientation": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => orientation?.toNativeValue(), + EnumMethod.value => orientation?.toValue(), + EnumMethod.name => orientation?.name() + }, "pagesAcross": pagesAcross, "pagesDown": pagesDown, "paperName": paperName, - "paperRect": paperRect?.toMap(), - "printableRect": printableRect?.toMap(), - "resolution": resolution?.toMap(), + "paperRect": paperRect?.toMap(enumMethod: enumMethod), + "printableRect": printableRect?.toMap(enumMethod: enumMethod), + "resolution": resolution?.toMap(enumMethod: enumMethod), "scalingFactor": scalingFactor, "time": time, - "verticalPagination": verticalPagination?.toNativeValue(), + "verticalPagination": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => verticalPagination?.toNativeValue(), + EnumMethod.value => verticalPagination?.toValue(), + EnumMethod.name => verticalPagination?.name() + }, }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/print_job_color_mode.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/print_job_color_mode.g.dart index 4bd1478f0..708a26af2 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/print_job_color_mode.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/print_job_color_mode.g.dart @@ -19,8 +19,8 @@ class PrintJobColorMode { ///Color color scheme, for example many colors are used. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- MacOS + ///- Android WebView + ///- macOS WKWebView static final COLOR = PrintJobColorMode._internalMultiPlatform(2, () { switch (defaultTargetPlatform) { case TargetPlatform.android: @@ -36,8 +36,8 @@ class PrintJobColorMode { ///Monochrome color scheme, for example one color is used. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- MacOS + ///- Android WebView + ///- macOS WKWebView static final MONOCHROME = PrintJobColorMode._internalMultiPlatform(1, () { switch (defaultTargetPlatform) { case TargetPlatform.android: @@ -82,26 +82,66 @@ class PrintJobColorMode { return null; } + /// Gets a possible [PrintJobColorMode] instance value with name [name]. + /// + /// Goes through [PrintJobColorMode.values] looking for a value with + /// name [name], as reported by [PrintJobColorMode.name]. + /// Returns the first value with the given name, otherwise `null`. + static PrintJobColorMode? byName(String? name) { + if (name != null) { + try { + return PrintJobColorMode.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [PrintJobColorMode] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in PrintJobColorMode.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; - ///Gets [dynamic] native value. + ///Gets [dynamic] native value if supported by the current platform, otherwise `null`. dynamic toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 2: + return 'COLOR'; + case 1: + return 'MONOCHROME'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + @override String toString() { - switch (_value) { - case 2: - return 'COLOR'; - case 1: - return 'MONOCHROME'; - } - return _value.toString(); + return name(); } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/print_job_disposition.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/print_job_disposition.g.dart index 65f090465..67c0a91b1 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/print_job_disposition.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/print_job_disposition.g.dart @@ -19,7 +19,7 @@ class PrintJobDisposition { ///Cancel print job. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView static final CANCEL = PrintJobDisposition._internalMultiPlatform('CANCEL', () { switch (defaultTargetPlatform) { @@ -34,7 +34,7 @@ class PrintJobDisposition { ///Send to Preview application. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView static final PREVIEW = PrintJobDisposition._internalMultiPlatform('PREVIEW', () { switch (defaultTargetPlatform) { @@ -49,7 +49,7 @@ class PrintJobDisposition { ///Save to a file. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView static final SAVE = PrintJobDisposition._internalMultiPlatform('SAVE', () { switch (defaultTargetPlatform) { case TargetPlatform.macOS: @@ -63,7 +63,7 @@ class PrintJobDisposition { ///Normal print job. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView static final SPOOL = PrintJobDisposition._internalMultiPlatform('SPOOL', () { switch (defaultTargetPlatform) { case TargetPlatform.macOS: @@ -108,18 +108,68 @@ class PrintJobDisposition { return null; } + /// Gets a possible [PrintJobDisposition] instance value with name [name]. + /// + /// Goes through [PrintJobDisposition.values] looking for a value with + /// name [name], as reported by [PrintJobDisposition.name]. + /// Returns the first value with the given name, otherwise `null`. + static PrintJobDisposition? byName(String? name) { + if (name != null) { + try { + return PrintJobDisposition.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [PrintJobDisposition] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in PrintJobDisposition.values) value.name(): value + }; + ///Gets [String] value. String toValue() => _value; ///Gets [String] native value. String toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'CANCEL': + return 'CANCEL'; + case 'PREVIEW': + return 'PREVIEW'; + case 'SAVE': + return 'SAVE'; + case 'SPOOL': + return 'SPOOL'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + @override String toString() { return _value; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/print_job_duplex_mode.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/print_job_duplex_mode.g.dart index fb607beca..2af3f61e0 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/print_job_duplex_mode.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/print_job_duplex_mode.g.dart @@ -20,9 +20,9 @@ class PrintJobDuplexMode { ///Pages are turned sideways along the long edge - like a book. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView static final LONG_EDGE = PrintJobDuplexMode._internalMultiPlatform('LONG_EDGE', () { switch (defaultTargetPlatform) { @@ -41,9 +41,9 @@ class PrintJobDuplexMode { ///No double-sided (duplex) printing; single-sided printing only. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView static final NONE = PrintJobDuplexMode._internalMultiPlatform('NONE', () { switch (defaultTargetPlatform) { case TargetPlatform.android: @@ -62,9 +62,9 @@ class PrintJobDuplexMode { ///Pages are turned upwards along the short edge - like a notepad. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView static final SHORT_EDGE = PrintJobDuplexMode._internalMultiPlatform('SHORT_EDGE', () { switch (defaultTargetPlatform) { @@ -113,18 +113,66 @@ class PrintJobDuplexMode { return null; } + /// Gets a possible [PrintJobDuplexMode] instance value with name [name]. + /// + /// Goes through [PrintJobDuplexMode.values] looking for a value with + /// name [name], as reported by [PrintJobDuplexMode.name]. + /// Returns the first value with the given name, otherwise `null`. + static PrintJobDuplexMode? byName(String? name) { + if (name != null) { + try { + return PrintJobDuplexMode.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [PrintJobDuplexMode] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in PrintJobDuplexMode.values) value.name(): value + }; + ///Gets [String] value. String toValue() => _value; - ///Gets [int?] native value. + ///Gets [int] native value if supported by the current platform, otherwise `null`. int? toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'LONG_EDGE': + return 'LONG_EDGE'; + case 'NONE': + return 'NONE'; + case 'SHORT_EDGE': + return 'SHORT_EDGE'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + @override String toString() { return _value; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/print_job_info.dart b/flutter_inappwebview_platform_interface/lib/src/types/print_job_info.dart index 6e9c16a69..eaf4fee13 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/print_job_info.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/print_job_info.dart @@ -6,6 +6,7 @@ import 'print_job_rendering_quality.dart'; import 'print_job_state.dart'; import 'print_job_page_order.dart'; import 'printer.dart'; +import 'enum_method.dart'; part 'print_job_info.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/print_job_info.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/print_job_info.g.dart index f65ecd164..c24a74ff8 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/print_job_info.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/print_job_info.g.dart @@ -139,13 +139,15 @@ class PrintJobInfo { this.state}); ///Gets a possible [PrintJobInfo] instance from a [Map] value. - static PrintJobInfo? fromMap(Map? map) { + static PrintJobInfo? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = PrintJobInfo( attributes: PrintJobAttributes.fromMap( - map['attributes']?.cast()), + map['attributes']?.cast(), + enumMethod: enumMethod), canSpawnSeparateThread: map['canSpawnSeparateThread'], copies: map['copies'], creationTime: map['creationTime'], @@ -155,21 +157,37 @@ class PrintJobInfo { label: map['label'], lastPage: map['lastPage'], numberOfPages: map['numberOfPages'], - pageOrder: PrintJobPageOrder.fromNativeValue(map['pageOrder']), - preferredRenderingQuality: PrintJobRenderingQuality.fromNativeValue( - map['preferredRenderingQuality']), - printer: Printer.fromMap(map['printer']?.cast()), + pageOrder: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + PrintJobPageOrder.fromNativeValue(map['pageOrder']), + EnumMethod.value => PrintJobPageOrder.fromValue(map['pageOrder']), + EnumMethod.name => PrintJobPageOrder.byName(map['pageOrder']) + }, + preferredRenderingQuality: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => PrintJobRenderingQuality.fromNativeValue( + map['preferredRenderingQuality']), + EnumMethod.value => + PrintJobRenderingQuality.fromValue(map['preferredRenderingQuality']), + EnumMethod.name => + PrintJobRenderingQuality.byName(map['preferredRenderingQuality']) + }, + printer: Printer.fromMap(map['printer']?.cast(), + enumMethod: enumMethod), showsPrintPanel: map['showsPrintPanel'], showsProgressPanel: map['showsProgressPanel'], - state: PrintJobState.fromNativeValue(map['state']), + state: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => PrintJobState.fromNativeValue(map['state']), + EnumMethod.value => PrintJobState.fromValue(map['state']), + EnumMethod.name => PrintJobState.byName(map['state']) + }, ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "attributes": attributes?.toMap(), + "attributes": attributes?.toMap(enumMethod: enumMethod), "canSpawnSeparateThread": canSpawnSeparateThread, "copies": copies, "creationTime": creationTime, @@ -179,12 +197,25 @@ class PrintJobInfo { "label": label, "lastPage": lastPage, "numberOfPages": numberOfPages, - "pageOrder": pageOrder?.toNativeValue(), - "preferredRenderingQuality": preferredRenderingQuality?.toNativeValue(), - "printer": printer?.toMap(), + "pageOrder": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => pageOrder?.toNativeValue(), + EnumMethod.value => pageOrder?.toValue(), + EnumMethod.name => pageOrder?.name() + }, + "preferredRenderingQuality": switch ( + enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => preferredRenderingQuality?.toNativeValue(), + EnumMethod.value => preferredRenderingQuality?.toValue(), + EnumMethod.name => preferredRenderingQuality?.name() + }, + "printer": printer?.toMap(enumMethod: enumMethod), "showsPrintPanel": showsPrintPanel, "showsProgressPanel": showsProgressPanel, - "state": state?.toNativeValue(), + "state": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => state?.toNativeValue(), + EnumMethod.value => state?.toValue(), + EnumMethod.name => state?.name() + }, }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/print_job_media_size.dart b/flutter_inappwebview_platform_interface/lib/src/types/print_job_media_size.dart index 828f86609..da7fc0c0b 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/print_job_media_size.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/print_job_media_size.dart @@ -1,6 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import '../print_job/main.dart'; +import 'enum_method.dart'; part 'print_job_media_size.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/print_job_media_size.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/print_job_media_size.g.dart index 038449c13..aabb967c2 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/print_job_media_size.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/print_job_media_size.g.dart @@ -417,7 +417,8 @@ class PrintJobMediaSize { required this.widthMils}); ///Gets a possible [PrintJobMediaSize] instance from a [Map] value. - static PrintJobMediaSize? fromMap(Map? map) { + static PrintJobMediaSize? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -431,7 +432,7 @@ class PrintJobMediaSize { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "heightMils": heightMils, "id": id, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/print_job_orientation.dart b/flutter_inappwebview_platform_interface/lib/src/types/print_job_orientation.dart index 259125ffc..2080141fe 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/print_job_orientation.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/print_job_orientation.dart @@ -13,12 +13,18 @@ class PrintJobOrientation_ { const PrintJobOrientation_._internal(this._value); ///Pages are printed in portrait orientation. - @EnumSupportedPlatforms( - platforms: [EnumIOSPlatform(value: 0), EnumMacOSPlatform(value: 0)]) + @EnumSupportedPlatforms(platforms: [ + EnumAndroidPlatform(value: 0), + EnumIOSPlatform(value: 0), + EnumMacOSPlatform(value: 0), + ]) static const PORTRAIT = const PrintJobOrientation_._internal(0); ///Pages are printed in landscape orientation. - @EnumSupportedPlatforms( - platforms: [EnumIOSPlatform(value: 1), EnumMacOSPlatform(value: 1)]) + @EnumSupportedPlatforms(platforms: [ + EnumAndroidPlatform(value: 1), + EnumIOSPlatform(value: 1), + EnumMacOSPlatform(value: 1), + ]) static const LANDSCAPE = const PrintJobOrientation_._internal(1); } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/print_job_orientation.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/print_job_orientation.g.dart index 334282859..74a124195 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/print_job_orientation.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/print_job_orientation.g.dart @@ -19,10 +19,13 @@ class PrintJobOrientation { ///Pages are printed in landscape orientation. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS - ///- MacOS + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView static final LANDSCAPE = PrintJobOrientation._internalMultiPlatform(1, () { switch (defaultTargetPlatform) { + case TargetPlatform.android: + return 1; case TargetPlatform.iOS: return 1; case TargetPlatform.macOS: @@ -36,10 +39,13 @@ class PrintJobOrientation { ///Pages are printed in portrait orientation. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS - ///- MacOS + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView static final PORTRAIT = PrintJobOrientation._internalMultiPlatform(0, () { switch (defaultTargetPlatform) { + case TargetPlatform.android: + return 0; case TargetPlatform.iOS: return 0; case TargetPlatform.macOS: @@ -82,26 +88,66 @@ class PrintJobOrientation { return null; } + /// Gets a possible [PrintJobOrientation] instance value with name [name]. + /// + /// Goes through [PrintJobOrientation.values] looking for a value with + /// name [name], as reported by [PrintJobOrientation.name]. + /// Returns the first value with the given name, otherwise `null`. + static PrintJobOrientation? byName(String? name) { + if (name != null) { + try { + return PrintJobOrientation.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [PrintJobOrientation] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in PrintJobOrientation.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 1: + return 'LANDSCAPE'; + case 0: + return 'PORTRAIT'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + @override String toString() { - switch (_value) { - case 1: - return 'LANDSCAPE'; - case 0: - return 'PORTRAIT'; - } - return _value.toString(); + return name(); } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/print_job_output_type.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/print_job_output_type.g.dart index c4b7ca7ff..a6e67a665 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/print_job_output_type.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/print_job_output_type.g.dart @@ -72,20 +72,44 @@ class PrintJobOutputType { return null; } + /// Gets a possible [PrintJobOutputType] instance value with name [name]. + /// + /// Goes through [PrintJobOutputType.values] looking for a value with + /// name [name], as reported by [PrintJobOutputType.name]. + /// Returns the first value with the given name, otherwise `null`. + static PrintJobOutputType? byName(String? name) { + if (name != null) { + try { + return PrintJobOutputType.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [PrintJobOutputType] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in PrintJobOutputType.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 0: return 'GENERAL'; @@ -98,4 +122,20 @@ class PrintJobOutputType { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/print_job_page_order.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/print_job_page_order.g.dart index bcbee904a..5f8cf77c8 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/print_job_page_order.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/print_job_page_order.g.dart @@ -19,7 +19,7 @@ class PrintJobPageOrder { ///Ascending (back to front) page order. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView static final ASCENDING = PrintJobPageOrder._internalMultiPlatform(1, () { switch (defaultTargetPlatform) { case TargetPlatform.macOS: @@ -33,7 +33,7 @@ class PrintJobPageOrder { ///Descending (front to back) page order. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView static final DESCENDING = PrintJobPageOrder._internalMultiPlatform(-1, () { switch (defaultTargetPlatform) { case TargetPlatform.macOS: @@ -47,7 +47,7 @@ class PrintJobPageOrder { ///The spooler does not rearrange pages—they are printed in the order received by the spooler. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView static final SPECIAL = PrintJobPageOrder._internalMultiPlatform(0, () { switch (defaultTargetPlatform) { case TargetPlatform.macOS: @@ -61,7 +61,7 @@ class PrintJobPageOrder { ///No page order specified. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView static final UNKNOWN = PrintJobPageOrder._internalMultiPlatform(2, () { switch (defaultTargetPlatform) { case TargetPlatform.macOS: @@ -106,20 +106,44 @@ class PrintJobPageOrder { return null; } + /// Gets a possible [PrintJobPageOrder] instance value with name [name]. + /// + /// Goes through [PrintJobPageOrder.values] looking for a value with + /// name [name], as reported by [PrintJobPageOrder.name]. + /// Returns the first value with the given name, otherwise `null`. + static PrintJobPageOrder? byName(String? name) { + if (name != null) { + try { + return PrintJobPageOrder.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [PrintJobPageOrder] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in PrintJobPageOrder.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 1: return 'ASCENDING'; @@ -132,4 +156,20 @@ class PrintJobPageOrder { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/print_job_pagination_mode.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/print_job_pagination_mode.g.dart index ec1da7bb5..07613cb56 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/print_job_pagination_mode.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/print_job_pagination_mode.g.dart @@ -19,7 +19,7 @@ class PrintJobPaginationMode { /// /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView static final AUTOMATIC = PrintJobPaginationMode._internalMultiPlatform('AUTOMATIC', () { switch (defaultTargetPlatform) { @@ -34,7 +34,7 @@ class PrintJobPaginationMode { /// /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView static final CLIP = PrintJobPaginationMode._internalMultiPlatform('CLIP', () { switch (defaultTargetPlatform) { case TargetPlatform.macOS: @@ -48,7 +48,7 @@ class PrintJobPaginationMode { /// /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView static final FIT = PrintJobPaginationMode._internalMultiPlatform('FIT', () { switch (defaultTargetPlatform) { case TargetPlatform.macOS: @@ -92,18 +92,66 @@ class PrintJobPaginationMode { return null; } + /// Gets a possible [PrintJobPaginationMode] instance value with name [name]. + /// + /// Goes through [PrintJobPaginationMode.values] looking for a value with + /// name [name], as reported by [PrintJobPaginationMode.name]. + /// Returns the first value with the given name, otherwise `null`. + static PrintJobPaginationMode? byName(String? name) { + if (name != null) { + try { + return PrintJobPaginationMode.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [PrintJobPaginationMode] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in PrintJobPaginationMode.values) value.name(): value + }; + ///Gets [String] value. String toValue() => _value; - ///Gets [int?] native value. + ///Gets [int] native value if supported by the current platform, otherwise `null`. int? toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'AUTOMATIC': + return 'AUTOMATIC'; + case 'CLIP': + return 'CLIP'; + case 'FIT': + return 'FIT'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + @override String toString() { return _value; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/print_job_rendering_quality.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/print_job_rendering_quality.g.dart index 70af46e3a..4da1a4454 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/print_job_rendering_quality.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/print_job_rendering_quality.g.dart @@ -19,8 +19,8 @@ class PrintJobRenderingQuality { ///Renders the printing at the best possible quality, regardless of speed. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS - ///- MacOS + ///- iOS WKWebView + ///- macOS WKWebView static final BEST = PrintJobRenderingQuality._internalMultiPlatform(0, () { switch (defaultTargetPlatform) { case TargetPlatform.iOS: @@ -37,8 +37,8 @@ class PrintJobRenderingQuality { ///This option should be used only after establishing that best quality rendering does indeed make the user interface unresponsive. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS - ///- MacOS + ///- iOS WKWebView + ///- macOS WKWebView static final RESPONSIVE = PrintJobRenderingQuality._internalMultiPlatform(1, () { switch (defaultTargetPlatform) { @@ -84,26 +84,66 @@ class PrintJobRenderingQuality { return null; } + /// Gets a possible [PrintJobRenderingQuality] instance value with name [name]. + /// + /// Goes through [PrintJobRenderingQuality.values] looking for a value with + /// name [name], as reported by [PrintJobRenderingQuality.name]. + /// Returns the first value with the given name, otherwise `null`. + static PrintJobRenderingQuality? byName(String? name) { + if (name != null) { + try { + return PrintJobRenderingQuality.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [PrintJobRenderingQuality] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in PrintJobRenderingQuality.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 0: + return 'BEST'; + case 1: + return 'RESPONSIVE'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + @override String toString() { - switch (_value) { - case 0: - return 'BEST'; - case 1: - return 'RESPONSIVE'; - } - return _value.toString(); + return name(); } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/print_job_resolution.dart b/flutter_inappwebview_platform_interface/lib/src/types/print_job_resolution.dart index cbbfd3c0f..f2ea665c9 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/print_job_resolution.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/print_job_resolution.dart @@ -1,6 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import '../print_job/main.dart'; +import 'enum_method.dart'; part 'print_job_resolution.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/print_job_resolution.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/print_job_resolution.g.dart index d5827269e..21a003182 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/print_job_resolution.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/print_job_resolution.g.dart @@ -34,7 +34,8 @@ class PrintJobResolution { required this.verticalDpi}); ///Gets a possible [PrintJobResolution] instance from a [Map] value. - static PrintJobResolution? fromMap(Map? map) { + static PrintJobResolution? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -48,7 +49,7 @@ class PrintJobResolution { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "horizontalDpi": horizontalDpi, "id": id, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/print_job_state.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/print_job_state.g.dart index 8a1efff62..9e2d3464e 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/print_job_state.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/print_job_state.g.dart @@ -21,7 +21,7 @@ class PrintJobState { ///Next valid states: [FAILED], [CANCELED], [STARTED]. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - PrintJobInfo.STATE_BLOCKED](https://developer.android.com/reference/android/print/PrintJobInfo#STATE_BLOCKED)) + ///- Android WebView ([Official API - PrintJobInfo.STATE_BLOCKED](https://developer.android.com/reference/android/print/PrintJobInfo#STATE_BLOCKED)) static final BLOCKED = PrintJobState._internalMultiPlatform(4, () { switch (defaultTargetPlatform) { case TargetPlatform.android: @@ -37,9 +37,9 @@ class PrintJobState { ///Next valid states: None. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - PrintJobInfo.STATE_CANCELED](https://developer.android.com/reference/android/print/PrintJobInfo#STATE_CANCELED)) - ///- iOS - ///- MacOS + ///- Android WebView ([Official API - PrintJobInfo.STATE_CANCELED](https://developer.android.com/reference/android/print/PrintJobInfo#STATE_CANCELED)) + ///- iOS WKWebView + ///- macOS WKWebView static final CANCELED = PrintJobState._internalMultiPlatform(7, () { switch (defaultTargetPlatform) { case TargetPlatform.android: @@ -59,9 +59,9 @@ class PrintJobState { ///Next valid states: None. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - PrintJobInfo.STATE_COMPLETED](https://developer.android.com/reference/android/print/PrintJobInfo#STATE_COMPLETED)) - ///- iOS - ///- MacOS + ///- Android WebView ([Official API - PrintJobInfo.STATE_COMPLETED](https://developer.android.com/reference/android/print/PrintJobInfo#STATE_COMPLETED)) + ///- iOS WKWebView + ///- macOS WKWebView static final COMPLETED = PrintJobState._internalMultiPlatform(5, () { switch (defaultTargetPlatform) { case TargetPlatform.android: @@ -81,9 +81,9 @@ class PrintJobState { ///Next valid states: [QUEUED]. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - PrintJobInfo.STATE_CREATED](https://developer.android.com/reference/android/print/PrintJobInfo#STATE_CREATED)) - ///- iOS - ///- MacOS + ///- Android WebView ([Official API - PrintJobInfo.STATE_CREATED](https://developer.android.com/reference/android/print/PrintJobInfo#STATE_CREATED)) + ///- iOS WKWebView + ///- macOS WKWebView static final CREATED = PrintJobState._internalMultiPlatform(1, () { switch (defaultTargetPlatform) { case TargetPlatform.android: @@ -103,8 +103,8 @@ class PrintJobState { ///Next valid states: None. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - PrintJobInfo.STATE_FAILED](https://developer.android.com/reference/android/print/PrintJobInfo#STATE_FAILED)) - ///- iOS + ///- Android WebView ([Official API - PrintJobInfo.STATE_FAILED](https://developer.android.com/reference/android/print/PrintJobInfo#STATE_FAILED)) + ///- iOS WKWebView static final FAILED = PrintJobState._internalMultiPlatform(6, () { switch (defaultTargetPlatform) { case TargetPlatform.android: @@ -122,7 +122,7 @@ class PrintJobState { ///Next valid states: [STARTED], [FAILED], [CANCELED]. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - PrintJobInfo.STATE_QUEUED](https://developer.android.com/reference/android/print/PrintJobInfo#STATE_QUEUED)) + ///- Android WebView ([Official API - PrintJobInfo.STATE_QUEUED](https://developer.android.com/reference/android/print/PrintJobInfo#STATE_QUEUED)) static final QUEUED = PrintJobState._internalMultiPlatform(2, () { switch (defaultTargetPlatform) { case TargetPlatform.android: @@ -138,9 +138,9 @@ class PrintJobState { ///Next valid states: [COMPLETED], [FAILED], [CANCELED], [BLOCKED]. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - PrintJobInfo.STATE_STARTED](https://developer.android.com/reference/android/print/PrintJobInfo#STATE_STARTED)) - ///- iOS - ///- MacOS + ///- Android WebView ([Official API - PrintJobInfo.STATE_STARTED](https://developer.android.com/reference/android/print/PrintJobInfo#STATE_STARTED)) + ///- iOS WKWebView + ///- macOS WKWebView static final STARTED = PrintJobState._internalMultiPlatform(3, () { switch (defaultTargetPlatform) { case TargetPlatform.android: @@ -192,20 +192,43 @@ class PrintJobState { return null; } + /// Gets a possible [PrintJobState] instance value with name [name]. + /// + /// Goes through [PrintJobState.values] looking for a value with + /// name [name], as reported by [PrintJobState.name]. + /// Returns the first value with the given name, otherwise `null`. + static PrintJobState? byName(String? name) { + if (name != null) { + try { + return PrintJobState.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [PrintJobState] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in PrintJobState.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; - ///Gets [int?] native value. + ///Gets [int] native value if supported by the current platform, otherwise `null`. int? toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 4: return 'BLOCKED'; @@ -224,4 +247,20 @@ class PrintJobState { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/printer.dart b/flutter_inappwebview_platform_interface/lib/src/types/printer.dart index f66c67b92..2216b49c6 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/printer.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/printer.dart @@ -1,6 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import '../print_job/main.dart'; +import 'enum_method.dart'; part 'printer.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/printer.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/printer.g.dart index ec54b75cf..0d422c4b8 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/printer.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/printer.g.dart @@ -11,31 +11,31 @@ class Printer { ///The unique id of the printer. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS + ///- Android WebView + ///- iOS WKWebView String? id; ///The PostScript language level recognized by the printer. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView int? languageLevel; ///The printer’s name. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView String? name; ///A description of the printer’s make and model. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView String? type; Printer({this.id, this.languageLevel, this.name, this.type}); ///Gets a possible [Printer] instance from a [Map] value. - static Printer? fromMap(Map? map) { + static Printer? fromMap(Map? map, {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -49,7 +49,7 @@ class Printer { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "id": id, "languageLevel": languageLevel, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/process_failed_detail.dart b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_detail.dart new file mode 100644 index 000000000..972807f91 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_detail.dart @@ -0,0 +1,77 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +import 'frame_info.dart'; +import 'process_failed_kind.dart'; +import 'process_failed_reason.dart'; +import 'enum_method.dart'; + +part 'process_failed_detail.g.dart'; + +///An object that contains information about a frame on a webpage. +@ExchangeableObject() +class ProcessFailedDetail_ { + ///The kind of process failure that has occurred. + @SupportedPlatforms(platforms: [ + WindowsPlatform(), + ]) + ProcessFailedKind_ kind; + + ///The exit code of the failing process, for telemetry purposes. + /// + ///The exit code is always STILL_ACTIVE (259) when [ProcessFailedKind.RENDER_PROCESS_UNRESPONSIVE]. + @SupportedPlatforms(platforms: [ + WindowsPlatform(), + ]) + int? exitCode; + + ///Description of the process assigned by the WebView2 Runtime. + /// + ///This is a technical English term appropriate for logging or development purposes, and not localized for the end user. + ///It applies to utility processes (for example, "Audio Service", "Video Capture") and plugin processes (for example, "Flash"). + ///The returned [processDescription] is empty if the WebView2 Runtime did not assign a description to the process. + @SupportedPlatforms(platforms: [ + WindowsPlatform(), + ]) + String? processDescription; + + ///The reason for the process failure. + @SupportedPlatforms(platforms: [ + WindowsPlatform(), + ]) + ProcessFailedReason_? reason; + + ///This property is the full path of the module that caused the crash in cases of Windows Code Integrity failures. + /// + ///Windows Code Integrity is a feature that verifies the integrity and authenticity of dynamic-link libraries (DLLs) on Windows systems. + ///It ensures that only trusted code can run on the system and prevents unauthorized or malicious modifications. + ///When ProcessFailed occurred due to a failed Code Integrity check, this property returns the full path of the file that was prevented from loading on the system. + ///The webview2 process which tried to load the DLL will fail with exit code STATUS_INVALID_IMAGE_HASH(-1073740760). + ///A file can fail integrity check for various reasons, such as: + ///- It has an invalid or missing signature that does not match the publisher or signer of the file. + ///- It has been tampered with or corrupted by malware or other software. + ///- It has been blocked by an administrator or a security policy. This property always will be the empty string if failure is not caused by STATUS_INVALID_IMAGE_HASH. + @SupportedPlatforms(platforms: [ + WindowsPlatform(), + ]) + String? failureSourceModulePath; + + ///The collection of [FrameInfo]s for frames in the WebView that were being rendered by the failed process. + /// + ///The content in these frames is replaced with an error page. + ///This is only available when [ProcessFailedKind] is [ProcessFailedKind.FRAME_RENDER_PROCESS_EXITED]; + ///frames is null for all other process failure kinds, including the case in which the failed process was the renderer + ///for the main frame and subframes within it, for which the failure kind is [ProcessFailedKind.RENDER_PROCESS_EXITED]. + @SupportedPlatforms(platforms: [ + WindowsPlatform(), + ]) + List? frameInfos; + + ProcessFailedDetail_({ + required this.kind, + this.exitCode, + this.processDescription, + this.reason, + this.failureSourceModulePath, + this.frameInfos, + }); +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/process_failed_detail.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_detail.g.dart new file mode 100644 index 000000000..ffda82c1d --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_detail.g.dart @@ -0,0 +1,135 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'process_failed_detail.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///An object that contains information about a frame on a webpage. +class ProcessFailedDetail { + ///The exit code of the failing process, for telemetry purposes. + /// + ///The exit code is always STILL_ACTIVE (259) when [ProcessFailedKind.RENDER_PROCESS_UNRESPONSIVE]. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 + int? exitCode; + + ///This property is the full path of the module that caused the crash in cases of Windows Code Integrity failures. + /// + ///Windows Code Integrity is a feature that verifies the integrity and authenticity of dynamic-link libraries (DLLs) on Windows systems. + ///It ensures that only trusted code can run on the system and prevents unauthorized or malicious modifications. + ///When ProcessFailed occurred due to a failed Code Integrity check, this property returns the full path of the file that was prevented from loading on the system. + ///The webview2 process which tried to load the DLL will fail with exit code STATUS_INVALID_IMAGE_HASH(-1073740760). + ///A file can fail integrity check for various reasons, such as: + ///- It has an invalid or missing signature that does not match the publisher or signer of the file. + ///- It has been tampered with or corrupted by malware or other software. + ///- It has been blocked by an administrator or a security policy. This property always will be the empty string if failure is not caused by STATUS_INVALID_IMAGE_HASH. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 + String? failureSourceModulePath; + + ///The collection of [FrameInfo]s for frames in the WebView that were being rendered by the failed process. + /// + ///The content in these frames is replaced with an error page. + ///This is only available when [ProcessFailedKind] is [ProcessFailedKind.FRAME_RENDER_PROCESS_EXITED]; + ///frames is null for all other process failure kinds, including the case in which the failed process was the renderer + ///for the main frame and subframes within it, for which the failure kind is [ProcessFailedKind.RENDER_PROCESS_EXITED]. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 + List? frameInfos; + + ///The kind of process failure that has occurred. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 + ProcessFailedKind kind; + + ///Description of the process assigned by the WebView2 Runtime. + /// + ///This is a technical English term appropriate for logging or development purposes, and not localized for the end user. + ///It applies to utility processes (for example, "Audio Service", "Video Capture") and plugin processes (for example, "Flash"). + ///The returned [processDescription] is empty if the WebView2 Runtime did not assign a description to the process. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 + String? processDescription; + + ///The reason for the process failure. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 + ProcessFailedReason? reason; + ProcessFailedDetail( + {this.exitCode, + this.failureSourceModulePath, + this.frameInfos, + required this.kind, + this.processDescription, + this.reason}); + + ///Gets a possible [ProcessFailedDetail] instance from a [Map] value. + static ProcessFailedDetail? fromMap(Map? map, + {EnumMethod? enumMethod}) { + if (map == null) { + return null; + } + final instance = ProcessFailedDetail( + exitCode: map['exitCode'], + failureSourceModulePath: map['failureSourceModulePath'], + frameInfos: map['frameInfos'] != null + ? List.from(map['frameInfos'].map((e) => FrameInfo.fromMap( + e?.cast(), + enumMethod: enumMethod)!)) + : null, + kind: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + ProcessFailedKind.fromNativeValue(map['kind']), + EnumMethod.value => ProcessFailedKind.fromValue(map['kind']), + EnumMethod.name => ProcessFailedKind.byName(map['kind']) + }!, + processDescription: map['processDescription'], + reason: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + ProcessFailedReason.fromNativeValue(map['reason']), + EnumMethod.value => ProcessFailedReason.fromValue(map['reason']), + EnumMethod.name => ProcessFailedReason.byName(map['reason']) + }, + ); + return instance; + } + + ///Converts instance to a map. + Map toMap({EnumMethod? enumMethod}) { + return { + "exitCode": exitCode, + "failureSourceModulePath": failureSourceModulePath, + "frameInfos": + frameInfos?.map((e) => e.toMap(enumMethod: enumMethod)).toList(), + "kind": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => kind.toNativeValue(), + EnumMethod.value => kind.toValue(), + EnumMethod.name => kind.name() + }, + "processDescription": processDescription, + "reason": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => reason?.toNativeValue(), + EnumMethod.value => reason?.toValue(), + EnumMethod.name => reason?.name() + }, + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'ProcessFailedDetail{exitCode: $exitCode, failureSourceModulePath: $failureSourceModulePath, frameInfos: $frameInfos, kind: $kind, processDescription: $processDescription, reason: $reason}'; + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/process_failed_kind.dart b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_kind.dart new file mode 100644 index 000000000..ebe30da23 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_kind.dart @@ -0,0 +1,152 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +part 'process_failed_kind.g.dart'; + +///Class used to indicate the kind of process failure that has occurred. +@ExchangeableEnum() +class ProcessFailedKind_ { + // ignore: unused_field + final String _value; + // ignore: unused_field + final int? _nativeValue = null; + const ProcessFailedKind_._internal(this._value); + + ///Indicates that the browser process ended unexpectedly. The WebView automatically moves to the Closed state. + ///The app has to recreate a new WebView to recover from this failure. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_BROWSER_PROCESS_EXITED', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 0), + ]) + static const BROWSER_PROCESS_EXITED = + const ProcessFailedKind_._internal('BROWSER_PROCESS_EXITED'); + + ///Indicates that the main frame's render process ended unexpectedly. Any subframes in the WebView will be gone too. + ///A new render process is created automatically and navigated to an error page. + ///You can use the reload method to try to recover from this failure. Alternatively, you can close and recreate the WebView. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_EXITED', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 1), + ]) + static const RENDER_PROCESS_EXITED = + const ProcessFailedKind_._internal('RENDER_PROCESS_EXITED'); + + ///Indicates that the main frame's render process is unresponsive. + ///Renderer process unresponsiveness can happen for the following reasons: + /// + ///* There is a **long-running script** being executed. For example, the + ///web content in your WebView might be performing a synchronous XHR, or have + ///entered an infinite loop. + ///* The **system is busy**. + /// + ///The process failed event will continue to be raised every few seconds + ///until the renderer process has become responsive again. The application + ///can consider taking action if the event keeps being raised. For example, + ///the application might show UI for the user to decide to keep waiting or + ///reload the page, or navigate away. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_UNRESPONSIVE', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 2), + ]) + static const RENDER_PROCESS_UNRESPONSIVE = + const ProcessFailedKind_._internal('RENDER_PROCESS_UNRESPONSIVE'); + + ///Indicates that a frame-only render process ended unexpectedly. + ///The process exit does not affect the top-level document, only a subset of the subframes within it. + ///The content in these frames is replaced with an error page in the frame. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_FRAME_RENDER_PROCESS_EXITED', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 3), + ]) + static const FRAME_RENDER_PROCESS_EXITED = + const ProcessFailedKind_._internal('FRAME_RENDER_PROCESS_EXITED'); + + ///Indicates that a utility process ended unexpectedly. + ///The failed process is recreated automatically. + ///Your application does not need to handle recovery for this event. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_UTILITY_PROCESS_EXITED', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 4), + ]) + static const UTILITY_PROCESS_EXITED = + const ProcessFailedKind_._internal('UTILITY_PROCESS_EXITED'); + + ///Indicates that a sandbox helper process ended unexpectedly. + ///This failure is not fatal. + ///Your application does not need to handle recovery for this event. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: + 'COREWEBVIEW2_PROCESS_FAILED_KIND_SANDBOX_HELPER_PROCESS_EXITED', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 5), + ]) + static const SANDBOX_HELPER_PROCESS_EXITED = + const ProcessFailedKind_._internal('SANDBOX_HELPER_PROCESS_EXITED'); + + ///Indicates that the GPU process ended unexpectedly. + ///The failed process is recreated automatically. + ///Your application does not need to handle recovery for this event. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_GPU_PROCESS_EXITED', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 6), + ]) + static const GPU_PROCESS_EXITED = + const ProcessFailedKind_._internal('GPU_PROCESS_EXITED'); + + ///Indicates that a PPAPI plugin process ended unexpectedly. + ///This failure is not fatal. + ///Your application does not need to handle recovery for this event. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_PLUGIN_PROCESS_EXITED', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 7), + ]) + static const PPAPI_PLUGIN_PROCESS_EXITED = + const ProcessFailedKind_._internal('PPAPI_PLUGIN_PROCESS_EXITED'); + + ///Indicates that a PPAPI plugin broker process ended unexpectedly. + ///This failure is not fatal. + ///Your application does not need to handle recovery for this event. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_BROKER_PROCESS_EXITED', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 8), + ]) + static const PPAPI_BROKER_PROCESS_EXITED = + const ProcessFailedKind_._internal('PPAPI_BROKER_PROCESS_EXITED'); + + ///Indicates that a process of unspecified kind ended unexpectedly. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_KIND_UNKNOWN_PROCESS_EXITED', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind', + value: 9), + ]) + static const UNKNOWN_PROCESS_EXITED = + const ProcessFailedKind_._internal('UNKNOWN_PROCESS_EXITED'); +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/process_failed_kind.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_kind.g.dart new file mode 100644 index 000000000..693ee5eb1 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_kind.g.dart @@ -0,0 +1,319 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'process_failed_kind.dart'; + +// ************************************************************************** +// ExchangeableEnumGenerator +// ************************************************************************** + +///Class used to indicate the kind of process failure that has occurred. +class ProcessFailedKind { + final String _value; + final int? _nativeValue; + const ProcessFailedKind._internal(this._value, this._nativeValue); +// ignore: unused_element + factory ProcessFailedKind._internalMultiPlatform( + String value, Function nativeValue) => + ProcessFailedKind._internal(value, nativeValue()); + + ///Indicates that the browser process ended unexpectedly. The WebView automatically moves to the Closed state. + ///The app has to recreate a new WebView to recover from this failure. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_BROWSER_PROCESS_EXITED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final BROWSER_PROCESS_EXITED = + ProcessFailedKind._internalMultiPlatform('BROWSER_PROCESS_EXITED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 0; + default: + break; + } + return null; + }); + + ///Indicates that a frame-only render process ended unexpectedly. + ///The process exit does not affect the top-level document, only a subset of the subframes within it. + ///The content in these frames is replaced with an error page in the frame. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_FRAME_RENDER_PROCESS_EXITED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final FRAME_RENDER_PROCESS_EXITED = + ProcessFailedKind._internalMultiPlatform('FRAME_RENDER_PROCESS_EXITED', + () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 3; + default: + break; + } + return null; + }); + + ///Indicates that the GPU process ended unexpectedly. + ///The failed process is recreated automatically. + ///Your application does not need to handle recovery for this event. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_GPU_PROCESS_EXITED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final GPU_PROCESS_EXITED = + ProcessFailedKind._internalMultiPlatform('GPU_PROCESS_EXITED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 6; + default: + break; + } + return null; + }); + + ///Indicates that a PPAPI plugin broker process ended unexpectedly. + ///This failure is not fatal. + ///Your application does not need to handle recovery for this event. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_BROKER_PROCESS_EXITED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final PPAPI_BROKER_PROCESS_EXITED = + ProcessFailedKind._internalMultiPlatform('PPAPI_BROKER_PROCESS_EXITED', + () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 8; + default: + break; + } + return null; + }); + + ///Indicates that a PPAPI plugin process ended unexpectedly. + ///This failure is not fatal. + ///Your application does not need to handle recovery for this event. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_PLUGIN_PROCESS_EXITED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final PPAPI_PLUGIN_PROCESS_EXITED = + ProcessFailedKind._internalMultiPlatform('PPAPI_PLUGIN_PROCESS_EXITED', + () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 7; + default: + break; + } + return null; + }); + + ///Indicates that the main frame's render process ended unexpectedly. Any subframes in the WebView will be gone too. + ///A new render process is created automatically and navigated to an error page. + ///You can use the reload method to try to recover from this failure. Alternatively, you can close and recreate the WebView. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_EXITED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final RENDER_PROCESS_EXITED = + ProcessFailedKind._internalMultiPlatform('RENDER_PROCESS_EXITED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 1; + default: + break; + } + return null; + }); + + ///Indicates that the main frame's render process is unresponsive. + ///Renderer process unresponsiveness can happen for the following reasons: + /// + ///* There is a **long-running script** being executed. For example, the + ///web content in your WebView might be performing a synchronous XHR, or have + ///entered an infinite loop. + ///* The **system is busy**. + /// + ///The process failed event will continue to be raised every few seconds + ///until the renderer process has become responsive again. The application + ///can consider taking action if the event keeps being raised. For example, + ///the application might show UI for the user to decide to keep waiting or + ///reload the page, or navigate away. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_UNRESPONSIVE](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final RENDER_PROCESS_UNRESPONSIVE = + ProcessFailedKind._internalMultiPlatform('RENDER_PROCESS_UNRESPONSIVE', + () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 2; + default: + break; + } + return null; + }); + + ///Indicates that a sandbox helper process ended unexpectedly. + ///This failure is not fatal. + ///Your application does not need to handle recovery for this event. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_SANDBOX_HELPER_PROCESS_EXITED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final SANDBOX_HELPER_PROCESS_EXITED = + ProcessFailedKind._internalMultiPlatform('SANDBOX_HELPER_PROCESS_EXITED', + () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 5; + default: + break; + } + return null; + }); + + ///Indicates that a process of unspecified kind ended unexpectedly. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_UNKNOWN_PROCESS_EXITED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final UNKNOWN_PROCESS_EXITED = + ProcessFailedKind._internalMultiPlatform('UNKNOWN_PROCESS_EXITED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 9; + default: + break; + } + return null; + }); + + ///Indicates that a utility process ended unexpectedly. + ///The failed process is recreated automatically. + ///Your application does not need to handle recovery for this event. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PROCESS_FAILED_KIND_UTILITY_PROCESS_EXITED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_kind)) + static final UTILITY_PROCESS_EXITED = + ProcessFailedKind._internalMultiPlatform('UTILITY_PROCESS_EXITED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 4; + default: + break; + } + return null; + }); + + ///Set of all values of [ProcessFailedKind]. + static final Set values = [ + ProcessFailedKind.BROWSER_PROCESS_EXITED, + ProcessFailedKind.FRAME_RENDER_PROCESS_EXITED, + ProcessFailedKind.GPU_PROCESS_EXITED, + ProcessFailedKind.PPAPI_BROKER_PROCESS_EXITED, + ProcessFailedKind.PPAPI_PLUGIN_PROCESS_EXITED, + ProcessFailedKind.RENDER_PROCESS_EXITED, + ProcessFailedKind.RENDER_PROCESS_UNRESPONSIVE, + ProcessFailedKind.SANDBOX_HELPER_PROCESS_EXITED, + ProcessFailedKind.UNKNOWN_PROCESS_EXITED, + ProcessFailedKind.UTILITY_PROCESS_EXITED, + ].toSet(); + + ///Gets a possible [ProcessFailedKind] instance from [String] value. + static ProcessFailedKind? fromValue(String? value) { + if (value != null) { + try { + return ProcessFailedKind.values + .firstWhere((element) => element.toValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + ///Gets a possible [ProcessFailedKind] instance from a native value. + static ProcessFailedKind? fromNativeValue(int? value) { + if (value != null) { + try { + return ProcessFailedKind.values + .firstWhere((element) => element.toNativeValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + /// Gets a possible [ProcessFailedKind] instance value with name [name]. + /// + /// Goes through [ProcessFailedKind.values] looking for a value with + /// name [name], as reported by [ProcessFailedKind.name]. + /// Returns the first value with the given name, otherwise `null`. + static ProcessFailedKind? byName(String? name) { + if (name != null) { + try { + return ProcessFailedKind.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [ProcessFailedKind] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in ProcessFailedKind.values) value.name(): value + }; + + ///Gets [String] value. + String toValue() => _value; + + ///Gets [int] native value if supported by the current platform, otherwise `null`. + int? toNativeValue() => _nativeValue; + + ///Gets the name of the value. + String name() { + switch (_value) { + case 'BROWSER_PROCESS_EXITED': + return 'BROWSER_PROCESS_EXITED'; + case 'FRAME_RENDER_PROCESS_EXITED': + return 'FRAME_RENDER_PROCESS_EXITED'; + case 'GPU_PROCESS_EXITED': + return 'GPU_PROCESS_EXITED'; + case 'PPAPI_BROKER_PROCESS_EXITED': + return 'PPAPI_BROKER_PROCESS_EXITED'; + case 'PPAPI_PLUGIN_PROCESS_EXITED': + return 'PPAPI_PLUGIN_PROCESS_EXITED'; + case 'RENDER_PROCESS_EXITED': + return 'RENDER_PROCESS_EXITED'; + case 'RENDER_PROCESS_UNRESPONSIVE': + return 'RENDER_PROCESS_UNRESPONSIVE'; + case 'SANDBOX_HELPER_PROCESS_EXITED': + return 'SANDBOX_HELPER_PROCESS_EXITED'; + case 'UNKNOWN_PROCESS_EXITED': + return 'UNKNOWN_PROCESS_EXITED'; + case 'UTILITY_PROCESS_EXITED': + return 'UTILITY_PROCESS_EXITED'; + } + return _value.toString(); + } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + + @override + String toString() { + return _value; + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/process_failed_reason.dart b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_reason.dart new file mode 100644 index 000000000..53ea7cf58 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_reason.dart @@ -0,0 +1,77 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +part 'process_failed_reason.g.dart'; + +///Class used to indicate the kind of process failure that has occurred. +@ExchangeableEnum() +class ProcessFailedReason_ { + // ignore: unused_field + final String _value; + // ignore: unused_field + final int? _nativeValue = null; + const ProcessFailedReason_._internal(this._value); + + ///An unexpected process failure occurred. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_REASON_UNEXPECTED', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', + value: 0), + ]) + static const UNEXPECTED = const ProcessFailedReason_._internal('UNEXPECTED'); + + ///The process became unresponsive. This only applies to the main frame's render process. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_REASON_UNRESPONSIVE', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', + value: 1), + ]) + static const UNRESPONSIVE = + const ProcessFailedReason_._internal('UNRESPONSIVE'); + + ///The process was terminated. For example, from Task Manager. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_REASON_TERMINATED', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', + value: 2), + ]) + static const TERMINATED = const ProcessFailedReason_._internal('TERMINATED'); + + ///The process crashed. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_REASON_CRASHED', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', + value: 3), + ]) + static const CRASHED = const ProcessFailedReason_._internal('CRASHED'); + + ///The process failed to launch. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_REASON_LAUNCH_FAILED', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', + value: 4), + ]) + static const LAUNCH_FAILED = + const ProcessFailedReason_._internal('LAUNCH_FAILED'); + + ///The process terminated due to running out of memory. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_PROCESS_FAILED_REASON_OUT_OF_MEMORY', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason', + value: 5), + ]) + static const OUT_OF_MEMORY = + const ProcessFailedReason_._internal('OUT_OF_MEMORY'); +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/process_failed_reason.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_reason.g.dart new file mode 100644 index 000000000..1516332c0 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/process_failed_reason.g.dart @@ -0,0 +1,215 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'process_failed_reason.dart'; + +// ************************************************************************** +// ExchangeableEnumGenerator +// ************************************************************************** + +///Class used to indicate the kind of process failure that has occurred. +class ProcessFailedReason { + final String _value; + final int? _nativeValue; + const ProcessFailedReason._internal(this._value, this._nativeValue); +// ignore: unused_element + factory ProcessFailedReason._internalMultiPlatform( + String value, Function nativeValue) => + ProcessFailedReason._internal(value, nativeValue()); + + ///The process crashed. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PROCESS_FAILED_REASON_CRASHED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason)) + static final CRASHED = + ProcessFailedReason._internalMultiPlatform('CRASHED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 3; + default: + break; + } + return null; + }); + + ///The process failed to launch. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PROCESS_FAILED_REASON_LAUNCH_FAILED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason)) + static final LAUNCH_FAILED = + ProcessFailedReason._internalMultiPlatform('LAUNCH_FAILED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 4; + default: + break; + } + return null; + }); + + ///The process terminated due to running out of memory. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PROCESS_FAILED_REASON_OUT_OF_MEMORY](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason)) + static final OUT_OF_MEMORY = + ProcessFailedReason._internalMultiPlatform('OUT_OF_MEMORY', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 5; + default: + break; + } + return null; + }); + + ///The process was terminated. For example, from Task Manager. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PROCESS_FAILED_REASON_TERMINATED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason)) + static final TERMINATED = + ProcessFailedReason._internalMultiPlatform('TERMINATED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 2; + default: + break; + } + return null; + }); + + ///An unexpected process failure occurred. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PROCESS_FAILED_REASON_UNEXPECTED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason)) + static final UNEXPECTED = + ProcessFailedReason._internalMultiPlatform('UNEXPECTED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 0; + default: + break; + } + return null; + }); + + ///The process became unresponsive. This only applies to the main frame's render process. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_PROCESS_FAILED_REASON_UNRESPONSIVE](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_process_failed_reason)) + static final UNRESPONSIVE = + ProcessFailedReason._internalMultiPlatform('UNRESPONSIVE', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 1; + default: + break; + } + return null; + }); + + ///Set of all values of [ProcessFailedReason]. + static final Set values = [ + ProcessFailedReason.CRASHED, + ProcessFailedReason.LAUNCH_FAILED, + ProcessFailedReason.OUT_OF_MEMORY, + ProcessFailedReason.TERMINATED, + ProcessFailedReason.UNEXPECTED, + ProcessFailedReason.UNRESPONSIVE, + ].toSet(); + + ///Gets a possible [ProcessFailedReason] instance from [String] value. + static ProcessFailedReason? fromValue(String? value) { + if (value != null) { + try { + return ProcessFailedReason.values + .firstWhere((element) => element.toValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + ///Gets a possible [ProcessFailedReason] instance from a native value. + static ProcessFailedReason? fromNativeValue(int? value) { + if (value != null) { + try { + return ProcessFailedReason.values + .firstWhere((element) => element.toNativeValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + /// Gets a possible [ProcessFailedReason] instance value with name [name]. + /// + /// Goes through [ProcessFailedReason.values] looking for a value with + /// name [name], as reported by [ProcessFailedReason.name]. + /// Returns the first value with the given name, otherwise `null`. + static ProcessFailedReason? byName(String? name) { + if (name != null) { + try { + return ProcessFailedReason.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [ProcessFailedReason] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in ProcessFailedReason.values) value.name(): value + }; + + ///Gets [String] value. + String toValue() => _value; + + ///Gets [int] native value if supported by the current platform, otherwise `null`. + int? toNativeValue() => _nativeValue; + + ///Gets the name of the value. + String name() { + switch (_value) { + case 'CRASHED': + return 'CRASHED'; + case 'LAUNCH_FAILED': + return 'LAUNCH_FAILED'; + case 'OUT_OF_MEMORY': + return 'OUT_OF_MEMORY'; + case 'TERMINATED': + return 'TERMINATED'; + case 'UNEXPECTED': + return 'UNEXPECTED'; + case 'UNRESPONSIVE': + return 'UNRESPONSIVE'; + } + return _value.toString(); + } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + + @override + String toString() { + return _value; + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/proxy_relay_hop.dart b/flutter_inappwebview_platform_interface/lib/src/types/proxy_relay_hop.dart new file mode 100644 index 000000000..52058f542 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/proxy_relay_hop.dart @@ -0,0 +1,46 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +import 'enum_method.dart'; + +part 'proxy_relay_hop.g.dart'; + +///Relay servers are secure HTTP proxies that allow proxying TCP traffic using the +///CONNECT method and UDP traffic using the connect-udp protocol defined in [RFC 9298](https://www.rfc-editor.org/rfc/rfc9298.html). +/// +///If [http3RelayEndpoint] is not null, it creates a configuration for a secure relay accessible using HTTP/3, with an optional HTTP/2 fallback using [http2RelayEndpoint]. +///Otherwise, if [http2RelayEndpoint] is not null, it sreates a configuration for a secure relay accessible only using HTTP/2. +/// +///At least one of [http3RelayEndpoint] or [http2RelayEndpoint] must be non-null. +@ExchangeableObject() +class ProxyRelayHop_ { + ///A URL or host endpoint identifying the relay server accessible using HTTP/3. + @SupportedPlatforms(platforms: [ + IOSPlatform(), + MacOSPlatform(), + ]) + String? http3RelayEndpoint; + + ///A URL or host endpoint identifying the relay server accessible using HTTP/2. + @SupportedPlatforms(platforms: [ + IOSPlatform(), + MacOSPlatform(), + ]) + String? http2RelayEndpoint; + + ///A dictionary of additional HTTP headers to send as part of CONNECT requests to the relay. + @SupportedPlatforms(platforms: [ + IOSPlatform(), + MacOSPlatform(), + ]) + Map? additionalHTTPHeaders; + + @ExchangeableObjectConstructor() + ProxyRelayHop_({ + this.http3RelayEndpoint, + this.http2RelayEndpoint, + this.additionalHTTPHeaders, + }) { + assert(http3RelayEndpoint != null || http2RelayEndpoint != null, + "At least one of http3RelayEndpoint or http2RelayEndpoint must be non-null"); + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/proxy_relay_hop.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/proxy_relay_hop.g.dart new file mode 100644 index 000000000..c5079e2e2 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/proxy_relay_hop.g.dart @@ -0,0 +1,78 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'proxy_relay_hop.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///Relay servers are secure HTTP proxies that allow proxying TCP traffic using the +///CONNECT method and UDP traffic using the connect-udp protocol defined in [RFC 9298](https://www.rfc-editor.org/rfc/rfc9298.html). +/// +///If [http3RelayEndpoint] is not null, it creates a configuration for a secure relay accessible using HTTP/3, with an optional HTTP/2 fallback using [http2RelayEndpoint]. +///Otherwise, if [http2RelayEndpoint] is not null, it sreates a configuration for a secure relay accessible only using HTTP/2. +/// +///At least one of [http3RelayEndpoint] or [http2RelayEndpoint] must be non-null. +class ProxyRelayHop { + ///A dictionary of additional HTTP headers to send as part of CONNECT requests to the relay. + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView + ///- macOS WKWebView + Map? additionalHTTPHeaders; + + ///A URL or host endpoint identifying the relay server accessible using HTTP/2. + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView + ///- macOS WKWebView + String? http2RelayEndpoint; + + ///A URL or host endpoint identifying the relay server accessible using HTTP/3. + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView + ///- macOS WKWebView + String? http3RelayEndpoint; + ProxyRelayHop( + {this.http3RelayEndpoint, + this.http2RelayEndpoint, + this.additionalHTTPHeaders}) { + assert(http3RelayEndpoint != null || http2RelayEndpoint != null, + "At least one of http3RelayEndpoint or http2RelayEndpoint must be non-null"); + } + + ///Gets a possible [ProxyRelayHop] instance from a [Map] value. + static ProxyRelayHop? fromMap(Map? map, + {EnumMethod? enumMethod}) { + if (map == null) { + return null; + } + final instance = ProxyRelayHop( + additionalHTTPHeaders: + map['additionalHTTPHeaders']?.cast(), + http2RelayEndpoint: map['http2RelayEndpoint'], + http3RelayEndpoint: map['http3RelayEndpoint'], + ); + return instance; + } + + ///Converts instance to a map. + Map toMap({EnumMethod? enumMethod}) { + return { + "additionalHTTPHeaders": additionalHTTPHeaders, + "http2RelayEndpoint": http2RelayEndpoint, + "http3RelayEndpoint": http3RelayEndpoint, + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'ProxyRelayHop{additionalHTTPHeaders: $additionalHTTPHeaders, http2RelayEndpoint: $http2RelayEndpoint, http3RelayEndpoint: $http3RelayEndpoint}'; + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/proxy_rule.dart b/flutter_inappwebview_platform_interface/lib/src/types/proxy_rule.dart index 031be516d..2a343f0c9 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/proxy_rule.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/proxy_rule.dart @@ -1,5 +1,6 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; +import 'enum_method.dart'; import 'proxy_scheme_filter.dart'; part 'proxy_rule.g.dart'; @@ -8,10 +9,64 @@ part 'proxy_rule.g.dart'; @ExchangeableObject() class ProxyRule_ { ///Represents the scheme filter. + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + ]) ProxySchemeFilter_? schemeFilter; ///Represents the proxy URL. + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + ]) String url; - ProxyRule_({required this.url, this.schemeFilter}); + ///A Boolean that indicates whether or not a proxy configuration allows failover to non-proxied connections. + ///Failover isn’t allowed by default. + @SupportedPlatforms(platforms: [ + IOSPlatform(), + MacOSPlatform(), + ]) + bool? allowFailover; + + ///Sets a username to use as authentication for a proxy configuration. + @SupportedPlatforms(platforms: [ + IOSPlatform(), + MacOSPlatform(), + ]) + String? username; + + ///Sets a password to use as authentication for a proxy configuration. + @SupportedPlatforms(platforms: [ + IOSPlatform(), + MacOSPlatform(), + ]) + String? password; + + ///Define an array of domains to determine which hosts should not use the proxy. + ///If the array is empty, no domains are excluded. + @SupportedPlatforms(platforms: [ + IOSPlatform(), + MacOSPlatform(), + ]) + List? excludedDomains; + + ///Define an array of domains to determine which hosts should use the proxy. If the array is empty, + ///all domains are allowed to use the proxy other than domains listed in [excludedDomains]. + @SupportedPlatforms(platforms: [ + IOSPlatform(), + MacOSPlatform(), + ]) + List? matchDomains; + + ProxyRule_({ + required this.url, + this.schemeFilter, + this.allowFailover, + this.username, + this.password, + this.excludedDomains, + this.matchDomains, + }); } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/proxy_rule.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/proxy_rule.g.dart index f81094c5c..2ac833531 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/proxy_rule.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/proxy_rule.g.dart @@ -8,30 +8,107 @@ part of 'proxy_rule.dart'; ///Class that holds a scheme filter and a proxy URL. class ProxyRule { + ///A Boolean that indicates whether or not a proxy configuration allows failover to non-proxied connections. + ///Failover isn’t allowed by default. + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView + ///- macOS WKWebView + bool? allowFailover; + + ///Define an array of domains to determine which hosts should not use the proxy. + ///If the array is empty, no domains are excluded. + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView + ///- macOS WKWebView + List? excludedDomains; + + ///Define an array of domains to determine which hosts should use the proxy. If the array is empty, + ///all domains are allowed to use the proxy other than domains listed in [excludedDomains]. + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView + ///- macOS WKWebView + List? matchDomains; + + ///Sets a password to use as authentication for a proxy configuration. + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView + ///- macOS WKWebView + String? password; + ///Represents the scheme filter. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView ProxySchemeFilter? schemeFilter; ///Represents the proxy URL. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView String url; - ProxyRule({this.schemeFilter, required this.url}); + + ///Sets a username to use as authentication for a proxy configuration. + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView + ///- macOS WKWebView + String? username; + ProxyRule( + {this.allowFailover, + this.excludedDomains, + this.matchDomains, + this.password, + this.schemeFilter, + required this.url, + this.username}); ///Gets a possible [ProxyRule] instance from a [Map] value. - static ProxyRule? fromMap(Map? map) { + static ProxyRule? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = ProxyRule( - schemeFilter: ProxySchemeFilter.fromNativeValue(map['schemeFilter']), + allowFailover: map['allowFailover'], + excludedDomains: map['excludedDomains'] != null + ? List.from(map['excludedDomains']!.cast()) + : null, + matchDomains: map['matchDomains'] != null + ? List.from(map['matchDomains']!.cast()) + : null, + password: map['password'], + schemeFilter: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + ProxySchemeFilter.fromNativeValue(map['schemeFilter']), + EnumMethod.value => ProxySchemeFilter.fromValue(map['schemeFilter']), + EnumMethod.name => ProxySchemeFilter.byName(map['schemeFilter']) + }, url: map['url'], + username: map['username'], ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "schemeFilter": schemeFilter?.toNativeValue(), + "allowFailover": allowFailover, + "excludedDomains": excludedDomains, + "matchDomains": matchDomains, + "password": password, + "schemeFilter": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => schemeFilter?.toNativeValue(), + EnumMethod.value => schemeFilter?.toValue(), + EnumMethod.name => schemeFilter?.name() + }, "url": url, + "username": username, }; } @@ -42,6 +119,6 @@ class ProxyRule { @override String toString() { - return 'ProxyRule{schemeFilter: $schemeFilter, url: $url}'; + return 'ProxyRule{allowFailover: $allowFailover, excludedDomains: $excludedDomains, matchDomains: $matchDomains, password: $password, schemeFilter: $schemeFilter, url: $url, username: $username}'; } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/proxy_scheme_filter.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/proxy_scheme_filter.g.dart index 7abc64a01..22b9d5dc8 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/proxy_scheme_filter.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/proxy_scheme_filter.g.dart @@ -58,18 +58,66 @@ class ProxySchemeFilter { return null; } + /// Gets a possible [ProxySchemeFilter] instance value with name [name]. + /// + /// Goes through [ProxySchemeFilter.values] looking for a value with + /// name [name], as reported by [ProxySchemeFilter.name]. + /// Returns the first value with the given name, otherwise `null`. + static ProxySchemeFilter? byName(String? name) { + if (name != null) { + try { + return ProxySchemeFilter.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [ProxySchemeFilter] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in ProxySchemeFilter.values) value.name(): value + }; + ///Gets [String] value. String toValue() => _value; ///Gets [String] native value. String toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case '*': + return 'MATCH_ALL_SCHEMES'; + case 'http': + return 'MATCH_HTTP'; + case 'https': + return 'MATCH_HTTPS'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { return _value; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/pull_to_refresh_size.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/pull_to_refresh_size.g.dart index bb53e8757..521de3753 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/pull_to_refresh_size.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/pull_to_refresh_size.g.dart @@ -54,27 +54,67 @@ class PullToRefreshSize { return null; } + /// Gets a possible [PullToRefreshSize] instance value with name [name]. + /// + /// Goes through [PullToRefreshSize.values] looking for a value with + /// name [name], as reported by [PullToRefreshSize.name]. + /// Returns the first value with the given name, otherwise `null`. + static PullToRefreshSize? byName(String? name) { + if (name != null) { + try { + return PullToRefreshSize.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [PullToRefreshSize] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in PullToRefreshSize.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 1: + return 'DEFAULT'; + case 0: + return 'LARGE'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { - switch (_value) { - case 1: - return 'DEFAULT'; - case 0: - return 'LARGE'; - } - return _value.toString(); + return name(); } } @@ -128,26 +168,66 @@ class AndroidPullToRefreshSize { return null; } + /// Gets a possible [AndroidPullToRefreshSize] instance value with name [name]. + /// + /// Goes through [AndroidPullToRefreshSize.values] looking for a value with + /// name [name], as reported by [AndroidPullToRefreshSize.name]. + /// Returns the first value with the given name, otherwise `null`. + static AndroidPullToRefreshSize? byName(String? name) { + if (name != null) { + try { + return AndroidPullToRefreshSize.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [AndroidPullToRefreshSize] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in AndroidPullToRefreshSize.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 1: + return 'DEFAULT'; + case 0: + return 'LARGE'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { - switch (_value) { - case 1: - return 'DEFAULT'; - case 0: - return 'LARGE'; - } - return _value.toString(); + return name(); } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/referrer_policy.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/referrer_policy.g.dart index db31b4b3d..855f98f47 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/referrer_policy.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/referrer_policy.g.dart @@ -91,18 +91,75 @@ class ReferrerPolicy { return null; } + /// Gets a possible [ReferrerPolicy] instance value with name [name]. + /// + /// Goes through [ReferrerPolicy.values] looking for a value with + /// name [name], as reported by [ReferrerPolicy.name]. + /// Returns the first value with the given name, otherwise `null`. + static ReferrerPolicy? byName(String? name) { + if (name != null) { + try { + return ReferrerPolicy.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [ReferrerPolicy] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in ReferrerPolicy.values) value.name(): value + }; + ///Gets [String] value. String toValue() => _value; ///Gets [String] native value. String toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'no-referrer': + return 'NO_REFERRER'; + case 'no-referrer-when-downgrade': + return 'NO_REFERRER_WHEN_DOWNGRADE'; + case 'origin': + return 'ORIGIN'; + case 'origin-when-cross-origin': + return 'ORIGIN_WHEN_CROSS_ORIGIN'; + case 'same-origin': + return 'SAME_ORIGIN'; + case 'strict-origin': + return 'STRICT_ORIGIN'; + case 'strict-origin-when-cross-origin': + return 'STRICT_ORIGIN_WHEN_CROSS_ORIGIN'; + case 'unsafe-url': + return 'UNSAFE_URL'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { return _value; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/render_process_gone_detail.dart b/flutter_inappwebview_platform_interface/lib/src/types/render_process_gone_detail.dart index 043a3cc82..c78c675d8 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/render_process_gone_detail.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/render_process_gone_detail.dart @@ -1,6 +1,8 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + import '../in_app_webview/platform_webview.dart'; import 'renderer_priority.dart'; +import 'enum_method.dart'; part 'render_process_gone_detail.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/render_process_gone_detail.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/render_process_gone_detail.g.dart index 39f2c3421..ae18a1e7f 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/render_process_gone_detail.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/render_process_gone_detail.g.dart @@ -21,23 +21,34 @@ class RenderProcessGoneDetail { {required this.didCrash, this.rendererPriorityAtExit}); ///Gets a possible [RenderProcessGoneDetail] instance from a [Map] value. - static RenderProcessGoneDetail? fromMap(Map? map) { + static RenderProcessGoneDetail? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = RenderProcessGoneDetail( didCrash: map['didCrash'], - rendererPriorityAtExit: + rendererPriorityAtExit: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => RendererPriority.fromNativeValue(map['rendererPriorityAtExit']), + EnumMethod.value => + RendererPriority.fromValue(map['rendererPriorityAtExit']), + EnumMethod.name => + RendererPriority.byName(map['rendererPriorityAtExit']) + }, ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "didCrash": didCrash, - "rendererPriorityAtExit": rendererPriorityAtExit?.toNativeValue(), + "rendererPriorityAtExit": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => rendererPriorityAtExit?.toNativeValue(), + EnumMethod.value => rendererPriorityAtExit?.toValue(), + EnumMethod.name => rendererPriorityAtExit?.name() + }, }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/renderer_priority.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/renderer_priority.g.dart index 2b2b7567a..513f7f467 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/renderer_priority.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/renderer_priority.g.dart @@ -59,20 +59,44 @@ class RendererPriority { return null; } + /// Gets a possible [RendererPriority] instance value with name [name]. + /// + /// Goes through [RendererPriority.values] looking for a value with + /// name [name], as reported by [RendererPriority.name]. + /// Returns the first value with the given name, otherwise `null`. + static RendererPriority? byName(String? name) { + if (name != null) { + try { + return RendererPriority.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [RendererPriority] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in RendererPriority.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 1: return 'RENDERER_PRIORITY_BOUND'; @@ -83,4 +107,20 @@ class RendererPriority { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/renderer_priority_policy.dart b/flutter_inappwebview_platform_interface/lib/src/types/renderer_priority_policy.dart index 8c599e964..5bb4fc794 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/renderer_priority_policy.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/renderer_priority_policy.dart @@ -1,6 +1,8 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + import '../in_app_webview/platform_webview.dart'; import 'renderer_priority.dart'; +import 'enum_method.dart'; part 'renderer_priority_policy.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/renderer_priority_policy.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/renderer_priority_policy.g.dart index 1ef810ea8..9e42b49a1 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/renderer_priority_policy.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/renderer_priority_policy.g.dart @@ -22,22 +22,34 @@ class RendererPriorityPolicy { {this.rendererRequestedPriority, required this.waivedWhenNotVisible}); ///Gets a possible [RendererPriorityPolicy] instance from a [Map] value. - static RendererPriorityPolicy? fromMap(Map? map) { + static RendererPriorityPolicy? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = RendererPriorityPolicy( - rendererRequestedPriority: + rendererRequestedPriority: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => RendererPriority.fromNativeValue(map['rendererRequestedPriority']), + EnumMethod.value => + RendererPriority.fromValue(map['rendererRequestedPriority']), + EnumMethod.name => + RendererPriority.byName(map['rendererRequestedPriority']) + }, waivedWhenNotVisible: map['waivedWhenNotVisible'], ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "rendererRequestedPriority": rendererRequestedPriority?.toNativeValue(), + "rendererRequestedPriority": switch ( + enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => rendererRequestedPriority?.toNativeValue(), + EnumMethod.value => rendererRequestedPriority?.toValue(), + EnumMethod.name => rendererRequestedPriority?.name() + }, "waivedWhenNotVisible": waivedWhenNotVisible, }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/request_focus_node_href_result.dart b/flutter_inappwebview_platform_interface/lib/src/types/request_focus_node_href_result.dart index 77f56c001..14d9d840c 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/request_focus_node_href_result.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/request_focus_node_href_result.dart @@ -2,6 +2,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_i import '../in_app_webview/platform_inappwebview_controller.dart'; import '../web_uri.dart'; +import 'enum_method.dart'; part 'request_focus_node_href_result.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/request_focus_node_href_result.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/request_focus_node_href_result.g.dart index 57c859404..eeea135fb 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/request_focus_node_href_result.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/request_focus_node_href_result.g.dart @@ -19,7 +19,8 @@ class RequestFocusNodeHrefResult { RequestFocusNodeHrefResult({this.src, this.title, this.url}); ///Gets a possible [RequestFocusNodeHrefResult] instance from a [Map] value. - static RequestFocusNodeHrefResult? fromMap(Map? map) { + static RequestFocusNodeHrefResult? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -32,7 +33,7 @@ class RequestFocusNodeHrefResult { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "src": src, "title": title, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/request_image_ref_result.dart b/flutter_inappwebview_platform_interface/lib/src/types/request_image_ref_result.dart index 0c5c622f3..c9f4eefc9 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/request_image_ref_result.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/request_image_ref_result.dart @@ -2,6 +2,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_i import '../in_app_webview/platform_inappwebview_controller.dart'; import '../web_uri.dart'; +import 'enum_method.dart'; part 'request_image_ref_result.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/request_image_ref_result.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/request_image_ref_result.g.dart index bb42cf518..758a7e002 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/request_image_ref_result.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/request_image_ref_result.g.dart @@ -13,7 +13,8 @@ class RequestImageRefResult { RequestImageRefResult({this.url}); ///Gets a possible [RequestImageRefResult] instance from a [Map] value. - static RequestImageRefResult? fromMap(Map? map) { + static RequestImageRefResult? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -24,7 +25,7 @@ class RequestImageRefResult { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "url": url?.toString(), }; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_response.dart b/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_response.dart index 35935cbba..940b52434 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_response.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_response.dart @@ -3,6 +3,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_i import '../in_app_webview/platform_inappwebview_controller.dart'; import '../in_app_webview/platform_webview.dart'; import 'safe_browsing_response_action.dart'; +import 'enum_method.dart'; part 'safe_browsing_response.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_response.g.dart index 4c24640e5..ffd1ae3a6 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_response.g.dart @@ -19,20 +19,32 @@ class SafeBrowsingResponse { this.report = true}); ///Gets a possible [SafeBrowsingResponse] instance from a [Map] value. - static SafeBrowsingResponse? fromMap(Map? map) { + static SafeBrowsingResponse? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = SafeBrowsingResponse(); - instance.action = SafeBrowsingResponseAction.fromNativeValue(map['action']); - instance.report = map['report']; + instance.action = switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + SafeBrowsingResponseAction.fromNativeValue(map['action']), + EnumMethod.value => SafeBrowsingResponseAction.fromValue(map['action']), + EnumMethod.name => SafeBrowsingResponseAction.byName(map['action']) + }; + if (map['report'] != null) { + instance.report = map['report']; + } return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "action": action?.toNativeValue(), + "action": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => action?.toNativeValue(), + EnumMethod.value => action?.toValue(), + EnumMethod.name => action?.name() + }, "report": report, }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_response_action.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_response_action.g.dart index c435bb404..683bf22ec 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_response_action.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_response_action.g.dart @@ -58,20 +58,45 @@ class SafeBrowsingResponseAction { return null; } + /// Gets a possible [SafeBrowsingResponseAction] instance value with name [name]. + /// + /// Goes through [SafeBrowsingResponseAction.values] looking for a value with + /// name [name], as reported by [SafeBrowsingResponseAction.name]. + /// Returns the first value with the given name, otherwise `null`. + static SafeBrowsingResponseAction? byName(String? name) { + if (name != null) { + try { + return SafeBrowsingResponseAction.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [SafeBrowsingResponseAction] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in SafeBrowsingResponseAction.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 0: return 'BACK_TO_SAFETY'; @@ -82,4 +107,20 @@ class SafeBrowsingResponseAction { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_threat.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_threat.g.dart index 763455f1e..f5413b450 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_threat.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/safe_browsing_threat.g.dart @@ -74,20 +74,44 @@ class SafeBrowsingThreat { return null; } + /// Gets a possible [SafeBrowsingThreat] instance value with name [name]. + /// + /// Goes through [SafeBrowsingThreat.values] looking for a value with + /// name [name], as reported by [SafeBrowsingThreat.name]. + /// Returns the first value with the given name, otherwise `null`. + static SafeBrowsingThreat? byName(String? name) { + if (name != null) { + try { + return SafeBrowsingThreat.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [SafeBrowsingThreat] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in SafeBrowsingThreat.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 4: return 'SAFE_BROWSING_THREAT_BILLING'; @@ -102,4 +126,20 @@ class SafeBrowsingThreat { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/sandbox.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/sandbox.g.dart index ca22db314..706ffe4ac 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/sandbox.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/sandbox.g.dart @@ -88,6 +88,34 @@ class Sandbox { Sandbox.ALLOW_TOP_NAVIGATION_BY_USER_ACTIVATION, ].toSet(); + /// Gets a possible [Sandbox] instance value with name [name]. + /// + /// Goes through [Sandbox.values] looking for a value with + /// name [name], as reported by [Sandbox.name]. + /// Returns the first value with the given name, otherwise `null`. + static Sandbox? byName(String? name) { + if (name != null) { + try { + return Sandbox.values.firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [Sandbox] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in Sandbox.values) value.name(): value + }; + ///Gets a possible [Sandbox] instance from a native value. static Sandbox? fromNativeValue(String? value) { if (value == null) { @@ -126,12 +154,52 @@ class Sandbox { return _value ?? ''; } - ///Gets [String?] native value. + ///Gets [String] native value if supported by the current platform, otherwise `null`. String? toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'null': + return 'ALLOW_ALL'; + case 'allow-downloads': + return 'ALLOW_DOWNLOADS'; + case 'allow-forms': + return 'ALLOW_FORMS'; + case 'allow-modals': + return 'ALLOW_MODALS'; + case 'null': + return 'ALLOW_NONE'; + case 'allow-orientation-lock': + return 'ALLOW_ORIENTATION_LOCK'; + case 'allow-pointer-lock': + return 'ALLOW_POINTER_LOCK'; + case 'allow-popups': + return 'ALLOW_POPUPS'; + case 'allow-popups-to-escape-sandbox': + return 'ALLOW_POPUPS_TO_ESCAPE_SANDBOX'; + case 'allow-presentation': + return 'ALLOW_PRESENTATION'; + case 'allow-same-origin': + return 'ALLOW_SAME_ORIGIN'; + case 'allow-scripts': + return 'ALLOW_SCRIPTS'; + case 'allow-top-navigation': + return 'ALLOW_TOP_NAVIGATION'; + case 'allow-top-navigation-by-user-activation': + return 'ALLOW_TOP_NAVIGATION_BY_USER_ACTIVATION'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/screenshot_configuration.dart b/flutter_inappwebview_platform_interface/lib/src/types/screenshot_configuration.dart index f08c5a81f..fe6b18137 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/screenshot_configuration.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/screenshot_configuration.dart @@ -3,6 +3,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_i import '../in_app_webview/platform_inappwebview_controller.dart'; import 'in_app_webview_rect.dart'; import 'compress_format.dart'; +import 'enum_method.dart'; part 'screenshot_configuration.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/screenshot_configuration.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/screenshot_configuration.g.dart index 460c7890d..e417d405b 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/screenshot_configuration.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/screenshot_configuration.g.dart @@ -13,18 +13,18 @@ class ScreenshotConfiguration { ///If you change the value to `false`, the `WebView` takes the snapshot immediately, and before incorporating any new changes. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS 13.0+ - ///- MacOS 10.15+ + ///- iOS WKWebView 13.0+ + ///- macOS WKWebView 10.15+ bool afterScreenUpdates; ///The compression format of the captured image. ///The default value is [CompressFormat.PNG]. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS - ///- Windows + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Windows WebView2 CompressFormat compressFormat; ///Use [afterScreenUpdates] instead. @@ -35,10 +35,10 @@ class ScreenshotConfiguration { ///[CompressFormat.PNG] is lossless, so this value is ignored. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS - ///- Windows + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Windows WebView2 int quality; ///The portion of your web view to capture, specified as a rectangle in the view’s coordinate system. @@ -46,10 +46,10 @@ class ScreenshotConfiguration { ///If you specify a custom rectangle, it must lie within the bounds rectangle of the `WebView` object. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS - ///- Windows + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Windows WebView2 InAppWebViewRect? rect; ///The width of the captured image, in points. @@ -59,9 +59,9 @@ class ScreenshotConfiguration { ///The default value of this property is `null`, which returns an image whose size matches the original size of the captured rectangle. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView double? snapshotWidth; ScreenshotConfiguration( {this.rect, @@ -77,29 +77,45 @@ class ScreenshotConfiguration { } ///Gets a possible [ScreenshotConfiguration] instance from a [Map] value. - static ScreenshotConfiguration? fromMap(Map? map) { + static ScreenshotConfiguration? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = ScreenshotConfiguration( iosAfterScreenUpdates: map['afterScreenUpdates'], - rect: InAppWebViewRect.fromMap(map['rect']?.cast()), + rect: InAppWebViewRect.fromMap(map['rect']?.cast(), + enumMethod: enumMethod), snapshotWidth: map['snapshotWidth'], ); - instance.afterScreenUpdates = map['afterScreenUpdates']; - instance.compressFormat = - CompressFormat.fromNativeValue(map['compressFormat'])!; - instance.quality = map['quality']; + if (map['afterScreenUpdates'] != null) { + instance.afterScreenUpdates = map['afterScreenUpdates']; + } + if (map['compressFormat'] != null) { + instance.compressFormat = switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + CompressFormat.fromNativeValue(map['compressFormat']), + EnumMethod.value => CompressFormat.fromValue(map['compressFormat']), + EnumMethod.name => CompressFormat.byName(map['compressFormat']) + }!; + } + if (map['quality'] != null) { + instance.quality = map['quality']; + } return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "afterScreenUpdates": afterScreenUpdates, - "compressFormat": compressFormat.toNativeValue(), + "compressFormat": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => compressFormat.toNativeValue(), + EnumMethod.value => compressFormat.toValue(), + EnumMethod.name => compressFormat.name() + }, "quality": quality, - "rect": rect?.toMap(), + "rect": rect?.toMap(enumMethod: enumMethod), "snapshotWidth": snapshotWidth, }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/script_html_tag_attributes.dart b/flutter_inappwebview_platform_interface/lib/src/types/script_html_tag_attributes.dart index 05a40266f..583ef1283 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/script_html_tag_attributes.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/script_html_tag_attributes.dart @@ -3,6 +3,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_i import '../in_app_webview/platform_inappwebview_controller.dart'; import 'cross_origin.dart'; import 'referrer_policy.dart'; +import 'enum_method.dart'; part 'script_html_tag_attributes.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/script_html_tag_attributes.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/script_html_tag_attributes.g.dart index 4ca725079..0d13f3fc7 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/script_html_tag_attributes.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/script_html_tag_attributes.g.dart @@ -86,35 +86,56 @@ class ScriptHtmlTagAttributes { } ///Gets a possible [ScriptHtmlTagAttributes] instance from a [Map] value. - static ScriptHtmlTagAttributes? fromMap(Map? map) { + static ScriptHtmlTagAttributes? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = ScriptHtmlTagAttributes( async: map['async'], - crossOrigin: CrossOrigin.fromNativeValue(map['crossOrigin']), + crossOrigin: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + CrossOrigin.fromNativeValue(map['crossOrigin']), + EnumMethod.value => CrossOrigin.fromValue(map['crossOrigin']), + EnumMethod.name => CrossOrigin.byName(map['crossOrigin']) + }, defer: map['defer'], id: map['id'], integrity: map['integrity'], noModule: map['noModule'], nonce: map['nonce'], - referrerPolicy: ReferrerPolicy.fromNativeValue(map['referrerPolicy']), + referrerPolicy: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + ReferrerPolicy.fromNativeValue(map['referrerPolicy']), + EnumMethod.value => ReferrerPolicy.fromValue(map['referrerPolicy']), + EnumMethod.name => ReferrerPolicy.byName(map['referrerPolicy']) + }, ); - instance.type = map['type']; + if (map['type'] != null) { + instance.type = map['type']; + } return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "async": async, - "crossOrigin": crossOrigin?.toNativeValue(), + "crossOrigin": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => crossOrigin?.toNativeValue(), + EnumMethod.value => crossOrigin?.toValue(), + EnumMethod.name => crossOrigin?.name() + }, "defer": defer, "id": id, "integrity": integrity, "noModule": noModule, "nonce": nonce, - "referrerPolicy": referrerPolicy?.toNativeValue(), + "referrerPolicy": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => referrerPolicy?.toNativeValue(), + EnumMethod.value => referrerPolicy?.toValue(), + EnumMethod.name => referrerPolicy?.name() + }, "type": type, }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/scrollbar_style.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/scrollbar_style.g.dart index 871f46754..21c24621d 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/scrollbar_style.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/scrollbar_style.g.dart @@ -75,20 +75,43 @@ class ScrollBarStyle { return null; } + /// Gets a possible [ScrollBarStyle] instance value with name [name]. + /// + /// Goes through [ScrollBarStyle.values] looking for a value with + /// name [name], as reported by [ScrollBarStyle.name]. + /// Returns the first value with the given name, otherwise `null`. + static ScrollBarStyle? byName(String? name) { + if (name != null) { + try { + return ScrollBarStyle.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [ScrollBarStyle] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in ScrollBarStyle.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 16777216: return 'SCROLLBARS_INSIDE_INSET'; @@ -101,6 +124,22 @@ class ScrollBarStyle { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } ///An Android-specific class used to configure the style of the scrollbars. @@ -176,20 +215,44 @@ class AndroidScrollBarStyle { return null; } + /// Gets a possible [AndroidScrollBarStyle] instance value with name [name]. + /// + /// Goes through [AndroidScrollBarStyle.values] looking for a value with + /// name [name], as reported by [AndroidScrollBarStyle.name]. + /// Returns the first value with the given name, otherwise `null`. + static AndroidScrollBarStyle? byName(String? name) { + if (name != null) { + try { + return AndroidScrollBarStyle.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [AndroidScrollBarStyle] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in AndroidScrollBarStyle.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 16777216: return 'SCROLLBARS_INSIDE_INSET'; @@ -202,4 +265,20 @@ class AndroidScrollBarStyle { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/scrollview_content_inset_adjustment_behavior.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/scrollview_content_inset_adjustment_behavior.g.dart index c53faec73..353682c87 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/scrollview_content_inset_adjustment_behavior.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/scrollview_content_inset_adjustment_behavior.g.dart @@ -66,20 +66,45 @@ class ScrollViewContentInsetAdjustmentBehavior { return null; } + /// Gets a possible [ScrollViewContentInsetAdjustmentBehavior] instance value with name [name]. + /// + /// Goes through [ScrollViewContentInsetAdjustmentBehavior.values] looking for a value with + /// name [name], as reported by [ScrollViewContentInsetAdjustmentBehavior.name]. + /// Returns the first value with the given name, otherwise `null`. + static ScrollViewContentInsetAdjustmentBehavior? byName(String? name) { + if (name != null) { + try { + return ScrollViewContentInsetAdjustmentBehavior.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [ScrollViewContentInsetAdjustmentBehavior] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in ScrollViewContentInsetAdjustmentBehavior.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 3: return 'ALWAYS'; @@ -92,6 +117,22 @@ class ScrollViewContentInsetAdjustmentBehavior { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } ///An iOS-specific class used to configure how safe area insets are added to the adjusted content inset. @@ -162,20 +203,46 @@ class IOSUIScrollViewContentInsetAdjustmentBehavior { return null; } + /// Gets a possible [IOSUIScrollViewContentInsetAdjustmentBehavior] instance value with name [name]. + /// + /// Goes through [IOSUIScrollViewContentInsetAdjustmentBehavior.values] looking for a value with + /// name [name], as reported by [IOSUIScrollViewContentInsetAdjustmentBehavior.name]. + /// Returns the first value with the given name, otherwise `null`. + static IOSUIScrollViewContentInsetAdjustmentBehavior? byName(String? name) { + if (name != null) { + try { + return IOSUIScrollViewContentInsetAdjustmentBehavior.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [IOSUIScrollViewContentInsetAdjustmentBehavior] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map + asNameMap() => { + for (final value + in IOSUIScrollViewContentInsetAdjustmentBehavior.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 3: return 'ALWAYS'; @@ -188,4 +255,20 @@ class IOSUIScrollViewContentInsetAdjustmentBehavior { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/scrollview_deceleration_rate.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/scrollview_deceleration_rate.g.dart index 2f64bd585..ffad421db 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/scrollview_deceleration_rate.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/scrollview_deceleration_rate.g.dart @@ -55,18 +55,65 @@ class ScrollViewDecelerationRate { return null; } + /// Gets a possible [ScrollViewDecelerationRate] instance value with name [name]. + /// + /// Goes through [ScrollViewDecelerationRate.values] looking for a value with + /// name [name], as reported by [ScrollViewDecelerationRate.name]. + /// Returns the first value with the given name, otherwise `null`. + static ScrollViewDecelerationRate? byName(String? name) { + if (name != null) { + try { + return ScrollViewDecelerationRate.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [ScrollViewDecelerationRate] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in ScrollViewDecelerationRate.values) + value.name(): value + }; + ///Gets [String] value. String toValue() => _value; ///Gets [String] native value. String toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'FAST': + return 'FAST'; + case 'NORMAL': + return 'NORMAL'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { return _value; @@ -125,18 +172,65 @@ class IOSUIScrollViewDecelerationRate { return null; } + /// Gets a possible [IOSUIScrollViewDecelerationRate] instance value with name [name]. + /// + /// Goes through [IOSUIScrollViewDecelerationRate.values] looking for a value with + /// name [name], as reported by [IOSUIScrollViewDecelerationRate.name]. + /// Returns the first value with the given name, otherwise `null`. + static IOSUIScrollViewDecelerationRate? byName(String? name) { + if (name != null) { + try { + return IOSUIScrollViewDecelerationRate.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [IOSUIScrollViewDecelerationRate] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in IOSUIScrollViewDecelerationRate.values) + value.name(): value + }; + ///Gets [String] value. String toValue() => _value; ///Gets [String] native value. String toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'FAST': + return 'FAST'; + case 'NORMAL': + return 'NORMAL'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { return _value; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/search_result_display_style.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/search_result_display_style.g.dart index 0f043309e..cc190e922 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/search_result_display_style.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/search_result_display_style.g.dart @@ -58,20 +58,44 @@ class SearchResultDisplayStyle { return null; } + /// Gets a possible [SearchResultDisplayStyle] instance value with name [name]. + /// + /// Goes through [SearchResultDisplayStyle.values] looking for a value with + /// name [name], as reported by [SearchResultDisplayStyle.name]. + /// Returns the first value with the given name, otherwise `null`. + static SearchResultDisplayStyle? byName(String? name) { + if (name != null) { + try { + return SearchResultDisplayStyle.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [SearchResultDisplayStyle] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in SearchResultDisplayStyle.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 0: return 'CURRENT_AND_TOTAL'; @@ -82,4 +106,20 @@ class SearchResultDisplayStyle { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/security_origin.dart b/flutter_inappwebview_platform_interface/lib/src/types/security_origin.dart index 958761f01..669077024 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/security_origin.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/security_origin.dart @@ -1,5 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; +import 'enum_method.dart'; + part 'security_origin.g.dart'; ///An object that identifies the origin of a particular resource. diff --git a/flutter_inappwebview_platform_interface/lib/src/types/security_origin.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/security_origin.g.dart index 4d0b53415..0afa630e7 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/security_origin.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/security_origin.g.dart @@ -20,7 +20,8 @@ class SecurityOrigin { {required this.host, required this.port, required this.protocol}); ///Gets a possible [SecurityOrigin] instance from a [Map] value. - static SecurityOrigin? fromMap(Map? map) { + static SecurityOrigin? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -33,7 +34,7 @@ class SecurityOrigin { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "host": host, "port": port, @@ -71,7 +72,8 @@ class IOSWKSecurityOrigin { {required this.host, required this.port, required this.protocol}); ///Gets a possible [IOSWKSecurityOrigin] instance from a [Map] value. - static IOSWKSecurityOrigin? fromMap(Map? map) { + static IOSWKSecurityOrigin? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -84,7 +86,7 @@ class IOSWKSecurityOrigin { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "host": host, "port": port, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/selection_granularity.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/selection_granularity.g.dart index 43acdd425..af5c5c9fa 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/selection_granularity.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/selection_granularity.g.dart @@ -54,27 +54,67 @@ class SelectionGranularity { return null; } + /// Gets a possible [SelectionGranularity] instance value with name [name]. + /// + /// Goes through [SelectionGranularity.values] looking for a value with + /// name [name], as reported by [SelectionGranularity.name]. + /// Returns the first value with the given name, otherwise `null`. + static SelectionGranularity? byName(String? name) { + if (name != null) { + try { + return SelectionGranularity.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [SelectionGranularity] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in SelectionGranularity.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 1: + return 'CHARACTER'; + case 0: + return 'DYNAMIC'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { - switch (_value) { - case 1: - return 'CHARACTER'; - case 0: - return 'DYNAMIC'; - } - return _value.toString(); + return name(); } } @@ -128,26 +168,67 @@ class IOSWKSelectionGranularity { return null; } + /// Gets a possible [IOSWKSelectionGranularity] instance value with name [name]. + /// + /// Goes through [IOSWKSelectionGranularity.values] looking for a value with + /// name [name], as reported by [IOSWKSelectionGranularity.name]. + /// Returns the first value with the given name, otherwise `null`. + static IOSWKSelectionGranularity? byName(String? name) { + if (name != null) { + try { + return IOSWKSelectionGranularity.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [IOSWKSelectionGranularity] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in IOSWKSelectionGranularity.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 1: + return 'CHARACTER'; + case 0: + return 'DYNAMIC'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { - switch (_value) { - case 1: - return 'CHARACTER'; - case 0: - return 'DYNAMIC'; - } - return _value.toString(); + return name(); } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/server_trust_auth_response.dart b/flutter_inappwebview_platform_interface/lib/src/types/server_trust_auth_response.dart index acfad82e5..e03d1e15a 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/server_trust_auth_response.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/server_trust_auth_response.dart @@ -1,6 +1,8 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + import '../in_app_webview/platform_webview.dart'; import 'server_trust_auth_response_action.dart'; +import 'enum_method.dart'; part 'server_trust_auth_response.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/server_trust_auth_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/server_trust_auth_response.g.dart index 4975dd74a..fdd3840a5 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/server_trust_auth_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/server_trust_auth_response.g.dart @@ -13,20 +13,30 @@ class ServerTrustAuthResponse { ServerTrustAuthResponse({this.action = ServerTrustAuthResponseAction.CANCEL}); ///Gets a possible [ServerTrustAuthResponse] instance from a [Map] value. - static ServerTrustAuthResponse? fromMap(Map? map) { + static ServerTrustAuthResponse? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = ServerTrustAuthResponse(); - instance.action = - ServerTrustAuthResponseAction.fromNativeValue(map['action']); + instance.action = switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + ServerTrustAuthResponseAction.fromNativeValue(map['action']), + EnumMethod.value => + ServerTrustAuthResponseAction.fromValue(map['action']), + EnumMethod.name => ServerTrustAuthResponseAction.byName(map['action']) + }; return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "action": action?.toNativeValue(), + "action": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => action?.toNativeValue(), + EnumMethod.value => action?.toValue(), + EnumMethod.name => action?.name() + }, }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/server_trust_auth_response_action.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/server_trust_auth_response_action.g.dart index 70ac9817a..a372d8d55 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/server_trust_auth_response_action.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/server_trust_auth_response_action.g.dart @@ -54,26 +54,67 @@ class ServerTrustAuthResponseAction { return null; } + /// Gets a possible [ServerTrustAuthResponseAction] instance value with name [name]. + /// + /// Goes through [ServerTrustAuthResponseAction.values] looking for a value with + /// name [name], as reported by [ServerTrustAuthResponseAction.name]. + /// Returns the first value with the given name, otherwise `null`. + static ServerTrustAuthResponseAction? byName(String? name) { + if (name != null) { + try { + return ServerTrustAuthResponseAction.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [ServerTrustAuthResponseAction] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in ServerTrustAuthResponseAction.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 0: + return 'CANCEL'; + case 1: + return 'PROCEED'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { - switch (_value) { - case 0: - return 'CANCEL'; - case 1: - return 'PROCEED'; - } - return _value.toString(); + return name(); } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/server_trust_challenge.dart b/flutter_inappwebview_platform_interface/lib/src/types/server_trust_challenge.dart index a1c66d596..86dd52b98 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/server_trust_challenge.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/server_trust_challenge.dart @@ -2,6 +2,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_i import 'url_authentication_challenge.dart'; import 'url_protection_space.dart'; +import 'enum_method.dart'; part 'server_trust_challenge.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/server_trust_challenge.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/server_trust_challenge.g.dart index 9db07d9cc..9b12ef419 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/server_trust_challenge.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/server_trust_challenge.g.dart @@ -13,21 +13,23 @@ class ServerTrustChallenge extends URLAuthenticationChallenge { : super(protectionSpace: protectionSpace); ///Gets a possible [ServerTrustChallenge] instance from a [Map] value. - static ServerTrustChallenge? fromMap(Map? map) { + static ServerTrustChallenge? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = ServerTrustChallenge( protectionSpace: URLProtectionSpace.fromMap( - map['protectionSpace']?.cast())!, + map['protectionSpace']?.cast(), + enumMethod: enumMethod)!, ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "protectionSpace": protectionSpace.toMap(), + "protectionSpace": protectionSpace.toMap(enumMethod: enumMethod), }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/should_allow_deprecated_tls_action.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/should_allow_deprecated_tls_action.g.dart index 378e44959..228b86a32 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/should_allow_deprecated_tls_action.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/should_allow_deprecated_tls_action.g.dart @@ -56,27 +56,68 @@ class ShouldAllowDeprecatedTLSAction { return null; } + /// Gets a possible [ShouldAllowDeprecatedTLSAction] instance value with name [name]. + /// + /// Goes through [ShouldAllowDeprecatedTLSAction.values] looking for a value with + /// name [name], as reported by [ShouldAllowDeprecatedTLSAction.name]. + /// Returns the first value with the given name, otherwise `null`. + static ShouldAllowDeprecatedTLSAction? byName(String? name) { + if (name != null) { + try { + return ShouldAllowDeprecatedTLSAction.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [ShouldAllowDeprecatedTLSAction] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in ShouldAllowDeprecatedTLSAction.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 1: + return 'ALLOW'; + case 0: + return 'CANCEL'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { - switch (_value) { - case 1: - return 'ALLOW'; - case 0: - return 'CANCEL'; - } - return _value.toString(); + return name(); } } @@ -132,26 +173,67 @@ class IOSShouldAllowDeprecatedTLSAction { return null; } + /// Gets a possible [IOSShouldAllowDeprecatedTLSAction] instance value with name [name]. + /// + /// Goes through [IOSShouldAllowDeprecatedTLSAction.values] looking for a value with + /// name [name], as reported by [IOSShouldAllowDeprecatedTLSAction.name]. + /// Returns the first value with the given name, otherwise `null`. + static IOSShouldAllowDeprecatedTLSAction? byName(String? name) { + if (name != null) { + try { + return IOSShouldAllowDeprecatedTLSAction.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [IOSShouldAllowDeprecatedTLSAction] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in IOSShouldAllowDeprecatedTLSAction.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 1: + return 'ALLOW'; + case 0: + return 'CANCEL'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { - switch (_value) { - case 1: - return 'ALLOW'; - case 0: - return 'CANCEL'; - } - return _value.toString(); + return name(); } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/show_file_chooser_request.dart b/flutter_inappwebview_platform_interface/lib/src/types/show_file_chooser_request.dart new file mode 100644 index 000000000..b9629036c --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/show_file_chooser_request.dart @@ -0,0 +1,39 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +import '../in_app_webview/platform_webview.dart'; +import 'show_file_chooser_request_mode.dart'; +import 'enum_method.dart'; + +part 'show_file_chooser_request.g.dart'; + +///Class used in the [PlatformWebViewCreationParams.onShowFileChooser] method. +@ExchangeableObject() +class ShowFileChooserRequest_ { + ///The file chooser mode. + final ShowFileChooserRequestMode_ mode; + + ///An array of acceptable MIME types. + ///The returned MIME type could be partial such as audio/*. + ///The array will be empty if no acceptable types are specified. + final List acceptTypes; + + ///Preference for a live media captured value (e. g. Camera, Microphone). + ///True indicates capture is enabled, false disabled. + ///Use [acceptTypes] to determine suitable capture devices. + final bool isCaptureEnabled; + + ///The title to use for this file selector. + ///If `null` a default title should be used. + final String? title; + + ///The file name of a default selection if specified, or `null`. + final String? filenameHint; + + ShowFileChooserRequest_({ + required this.mode, + required this.acceptTypes, + required this.isCaptureEnabled, + this.title, + this.filenameHint, + }); +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/show_file_chooser_request.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/show_file_chooser_request.g.dart new file mode 100644 index 000000000..14d951687 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/show_file_chooser_request.g.dart @@ -0,0 +1,82 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'show_file_chooser_request.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///Class used in the [PlatformWebViewCreationParams.onShowFileChooser] method. +class ShowFileChooserRequest { + ///An array of acceptable MIME types. + ///The returned MIME type could be partial such as audio/*. + ///The array will be empty if no acceptable types are specified. + final List acceptTypes; + + ///The file name of a default selection if specified, or `null`. + final String? filenameHint; + + ///Preference for a live media captured value (e. g. Camera, Microphone). + ///True indicates capture is enabled, false disabled. + ///Use [acceptTypes] to determine suitable capture devices. + final bool isCaptureEnabled; + + ///The file chooser mode. + final ShowFileChooserRequestMode mode; + + ///The title to use for this file selector. + ///If `null` a default title should be used. + final String? title; + ShowFileChooserRequest( + {required this.acceptTypes, + this.filenameHint, + required this.isCaptureEnabled, + required this.mode, + this.title}); + + ///Gets a possible [ShowFileChooserRequest] instance from a [Map] value. + static ShowFileChooserRequest? fromMap(Map? map, + {EnumMethod? enumMethod}) { + if (map == null) { + return null; + } + final instance = ShowFileChooserRequest( + acceptTypes: List.from(map['acceptTypes']!.cast()), + filenameHint: map['filenameHint'], + isCaptureEnabled: map['isCaptureEnabled'], + mode: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + ShowFileChooserRequestMode.fromNativeValue(map['mode']), + EnumMethod.value => ShowFileChooserRequestMode.fromValue(map['mode']), + EnumMethod.name => ShowFileChooserRequestMode.byName(map['mode']) + }!, + title: map['title'], + ); + return instance; + } + + ///Converts instance to a map. + Map toMap({EnumMethod? enumMethod}) { + return { + "acceptTypes": acceptTypes, + "filenameHint": filenameHint, + "isCaptureEnabled": isCaptureEnabled, + "mode": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => mode.toNativeValue(), + EnumMethod.value => mode.toValue(), + EnumMethod.name => mode.name() + }, + "title": title, + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'ShowFileChooserRequest{acceptTypes: $acceptTypes, filenameHint: $filenameHint, isCaptureEnabled: $isCaptureEnabled, mode: $mode, title: $title}'; + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/show_file_chooser_request_mode.dart b/flutter_inappwebview_platform_interface/lib/src/types/show_file_chooser_request_mode.dart new file mode 100644 index 000000000..e51f67d19 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/show_file_chooser_request_mode.dart @@ -0,0 +1,33 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; +import 'show_file_chooser_request.dart'; + +part 'show_file_chooser_request_mode.g.dart'; + +///It represents file chooser mode of a [ShowFileChooserRequest]. +@ExchangeableEnum() +class ShowFileChooserRequestMode_ { + // ignore: unused_field + final int _value; + // ignore: unused_field + final int? _nativeValue = null; + const ShowFileChooserRequestMode_._internal(this._value); + + ///Open single file. Requires that the file exists before allowing the user to pick it. + @EnumSupportedPlatforms(platforms: [EnumAndroidPlatform(value: 0)]) + static const OPEN = const ShowFileChooserRequestMode_._internal(0); + + ///Like Open but allows multiple files to be selected. + @EnumSupportedPlatforms(platforms: [EnumAndroidPlatform(value: 1)]) + static const OPEN_MULTIPLE = const ShowFileChooserRequestMode_._internal(1); + + ///Like Open but allows a folder to be selected. + ///The implementation should enumerate all files selected by this operation. + ///This feature is not supported at the moment. + @EnumSupportedPlatforms(platforms: [EnumAndroidPlatform(value: 2)]) + static const OPEN_FOLDER = const ShowFileChooserRequestMode_._internal(2); + + ///Allows picking a nonexistent file and saving it. + @EnumSupportedPlatforms(platforms: [EnumAndroidPlatform(value: 3)]) + static const SAVE = const ShowFileChooserRequestMode_._internal(3); +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/show_file_chooser_request_mode.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/show_file_chooser_request_mode.g.dart new file mode 100644 index 000000000..6a48ef42a --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/show_file_chooser_request_mode.g.dart @@ -0,0 +1,180 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'show_file_chooser_request_mode.dart'; + +// ************************************************************************** +// ExchangeableEnumGenerator +// ************************************************************************** + +///It represents file chooser mode of a [ShowFileChooserRequest]. +class ShowFileChooserRequestMode { + final int _value; + final int? _nativeValue; + const ShowFileChooserRequestMode._internal(this._value, this._nativeValue); +// ignore: unused_element + factory ShowFileChooserRequestMode._internalMultiPlatform( + int value, Function nativeValue) => + ShowFileChooserRequestMode._internal(value, nativeValue()); + + ///Open single file. Requires that the file exists before allowing the user to pick it. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + static final OPEN = ShowFileChooserRequestMode._internalMultiPlatform(0, () { + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return 0; + default: + break; + } + return null; + }); + + ///Like Open but allows a folder to be selected. + ///The implementation should enumerate all files selected by this operation. + ///This feature is not supported at the moment. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + static final OPEN_FOLDER = + ShowFileChooserRequestMode._internalMultiPlatform(2, () { + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return 2; + default: + break; + } + return null; + }); + + ///Like Open but allows multiple files to be selected. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + static final OPEN_MULTIPLE = + ShowFileChooserRequestMode._internalMultiPlatform(1, () { + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return 1; + default: + break; + } + return null; + }); + + ///Allows picking a nonexistent file and saving it. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + static final SAVE = ShowFileChooserRequestMode._internalMultiPlatform(3, () { + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return 3; + default: + break; + } + return null; + }); + + ///Set of all values of [ShowFileChooserRequestMode]. + static final Set values = [ + ShowFileChooserRequestMode.OPEN, + ShowFileChooserRequestMode.OPEN_FOLDER, + ShowFileChooserRequestMode.OPEN_MULTIPLE, + ShowFileChooserRequestMode.SAVE, + ].toSet(); + + ///Gets a possible [ShowFileChooserRequestMode] instance from [int] value. + static ShowFileChooserRequestMode? fromValue(int? value) { + if (value != null) { + try { + return ShowFileChooserRequestMode.values + .firstWhere((element) => element.toValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + ///Gets a possible [ShowFileChooserRequestMode] instance from a native value. + static ShowFileChooserRequestMode? fromNativeValue(int? value) { + if (value != null) { + try { + return ShowFileChooserRequestMode.values + .firstWhere((element) => element.toNativeValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + /// Gets a possible [ShowFileChooserRequestMode] instance value with name [name]. + /// + /// Goes through [ShowFileChooserRequestMode.values] looking for a value with + /// name [name], as reported by [ShowFileChooserRequestMode.name]. + /// Returns the first value with the given name, otherwise `null`. + static ShowFileChooserRequestMode? byName(String? name) { + if (name != null) { + try { + return ShowFileChooserRequestMode.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [ShowFileChooserRequestMode] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in ShowFileChooserRequestMode.values) + value.name(): value + }; + + ///Gets [int] value. + int toValue() => _value; + + ///Gets [int] native value if supported by the current platform, otherwise `null`. + int? toNativeValue() => _nativeValue; + + ///Gets the name of the value. + String name() { + switch (_value) { + case 0: + return 'OPEN'; + case 2: + return 'OPEN_FOLDER'; + case 1: + return 'OPEN_MULTIPLE'; + case 3: + return 'SAVE'; + } + return _value.toString(); + } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + + @override + String toString() { + return name(); + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/show_file_chooser_response.dart b/flutter_inappwebview_platform_interface/lib/src/types/show_file_chooser_response.dart new file mode 100644 index 000000000..638c23d77 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/show_file_chooser_response.dart @@ -0,0 +1,22 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +import '../in_app_webview/platform_webview.dart'; +import 'enum_method.dart'; + +part 'show_file_chooser_response.g.dart'; + +///Class used in the [PlatformWebViewCreationParams.onShowFileChooser] method. +@ExchangeableObject() +class ShowFileChooserResponse_ { + ///Whether the file chooser request was handled by the client. + final bool handledByClient; + + ///The file paths of the selected files or `null` to cancel the request. + ///Each file path must be a valid file URI using the "file:" scheme. + final List? filePaths; + + ShowFileChooserResponse_({ + required this.handledByClient, + this.filePaths, + }); +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/show_file_chooser_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/show_file_chooser_response.g.dart new file mode 100644 index 000000000..66eeb7dea --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/show_file_chooser_response.g.dart @@ -0,0 +1,51 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'show_file_chooser_response.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///Class used in the [PlatformWebViewCreationParams.onShowFileChooser] method. +class ShowFileChooserResponse { + ///The file paths of the selected files or `null` to cancel the request. + ///Each file path must be a valid file URI using the "file:" scheme. + final List? filePaths; + + ///Whether the file chooser request was handled by the client. + final bool handledByClient; + ShowFileChooserResponse({this.filePaths, required this.handledByClient}); + + ///Gets a possible [ShowFileChooserResponse] instance from a [Map] value. + static ShowFileChooserResponse? fromMap(Map? map, + {EnumMethod? enumMethod}) { + if (map == null) { + return null; + } + final instance = ShowFileChooserResponse( + filePaths: map['filePaths'] != null + ? List.from(map['filePaths']!.cast()) + : null, + handledByClient: map['handledByClient'], + ); + return instance; + } + + ///Converts instance to a map. + Map toMap({EnumMethod? enumMethod}) { + return { + "filePaths": filePaths, + "handledByClient": handledByClient, + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'ShowFileChooserResponse{filePaths: $filePaths, handledByClient: $handledByClient}'; + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/ssl_certificate.dart b/flutter_inappwebview_platform_interface/lib/src/types/ssl_certificate.dart index 041cfabd4..35c3a3a22 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/ssl_certificate.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/ssl_certificate.dart @@ -3,6 +3,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_i import '../util.dart'; import '../x509_certificate/x509_certificate.dart'; import '../x509_certificate/asn1_distinguished_names.dart'; +import 'enum_method.dart'; import 'ssl_certificate_dname.dart'; @@ -34,7 +35,8 @@ class SslCertificate_ { this.x509Certificate}); ///Gets a possible [SslCertificate] instance from a [Map] value. - static SslCertificate? fromMap(Map? map) { + static SslCertificate? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -81,10 +83,12 @@ class SslCertificate_ { } return SslCertificate( - issuedBy: - SslCertificateDName.fromMap(map["issuedBy"]?.cast()), - issuedTo: - SslCertificateDName.fromMap(map["issuedTo"]?.cast()), + issuedBy: SslCertificateDName.fromMap( + map["issuedBy"]?.cast(), + enumMethod: enumMethod), + issuedTo: SslCertificateDName.fromMap( + map["issuedTo"]?.cast(), + enumMethod: enumMethod), validNotAfterDate: map["validNotAfterDate"] != null ? DateTime.fromMillisecondsSinceEpoch(map["validNotAfterDate"]) : null, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/ssl_certificate.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/ssl_certificate.g.dart index d98b03127..8d548c6f8 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/ssl_certificate.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/ssl_certificate.g.dart @@ -30,7 +30,8 @@ class SslCertificate { this.x509Certificate}); ///Gets a possible [SslCertificate] instance from a [Map] value. - static SslCertificate? fromMap(Map? map) { + static SslCertificate? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -72,9 +73,11 @@ class SslCertificate { } return SslCertificate( issuedBy: SslCertificateDName.fromMap( - map["issuedBy"]?.cast()), + map["issuedBy"]?.cast(), + enumMethod: enumMethod), issuedTo: SslCertificateDName.fromMap( - map["issuedTo"]?.cast()), + map["issuedTo"]?.cast(), + enumMethod: enumMethod), validNotAfterDate: map["validNotAfterDate"] != null ? DateTime.fromMillisecondsSinceEpoch(map["validNotAfterDate"]) : null, @@ -85,13 +88,13 @@ class SslCertificate { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "issuedBy": issuedBy?.toMap(), - "issuedTo": issuedTo?.toMap(), + "issuedBy": issuedBy?.toMap(enumMethod: enumMethod), + "issuedTo": issuedTo?.toMap(enumMethod: enumMethod), "validNotAfterDate": validNotAfterDate?.millisecondsSinceEpoch, "validNotBeforeDate": validNotBeforeDate?.millisecondsSinceEpoch, - "x509Certificate": x509Certificate?.toMap(), + "x509Certificate": x509Certificate?.toMap(enumMethod: enumMethod), }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/ssl_certificate_dname.dart b/flutter_inappwebview_platform_interface/lib/src/types/ssl_certificate_dname.dart index fba647b10..79822a0fb 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/ssl_certificate_dname.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/ssl_certificate_dname.dart @@ -1,5 +1,6 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; +import 'enum_method.dart'; import 'ssl_certificate.dart'; part 'ssl_certificate_dname.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/ssl_certificate_dname.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/ssl_certificate_dname.g.dart index 3231eb69c..b6ac1c5c2 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/ssl_certificate_dname.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/ssl_certificate_dname.g.dart @@ -23,7 +23,8 @@ class SslCertificateDName { {this.CName = "", this.DName = "", this.OName = "", this.UName = ""}); ///Gets a possible [SslCertificateDName] instance from a [Map] value. - static SslCertificateDName? fromMap(Map? map) { + static SslCertificateDName? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -36,7 +37,7 @@ class SslCertificateDName { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "CName": CName, "DName": DName, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/ssl_error.dart b/flutter_inappwebview_platform_interface/lib/src/types/ssl_error.dart index 1971d8405..4a3d73923 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/ssl_error.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/ssl_error.dart @@ -1,5 +1,6 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; +import 'enum_method.dart'; import 'ssl_error_type.dart'; part 'ssl_error.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/ssl_error.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/ssl_error.g.dart index 1f838bc3c..1aeec754b 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/ssl_error.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/ssl_error.g.dart @@ -32,23 +32,40 @@ class SslError { } ///Gets a possible [SslError] instance from a [Map] value. - static SslError? fromMap(Map? map) { + static SslError? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = SslError( - androidError: AndroidSslError.fromNativeValue(map['code']), - code: SslErrorType.fromNativeValue(map['code']), - iosError: IOSSslError.fromNativeValue(map['code']), + androidError: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => AndroidSslError.fromNativeValue(map['code']), + EnumMethod.value => AndroidSslError.fromValue(map['code']), + EnumMethod.name => AndroidSslError.byName(map['code']) + }, + code: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => SslErrorType.fromNativeValue(map['code']), + EnumMethod.value => SslErrorType.fromValue(map['code']), + EnumMethod.name => SslErrorType.byName(map['code']) + }, + iosError: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => IOSSslError.fromNativeValue(map['code']), + EnumMethod.value => IOSSslError.fromValue(map['code']), + EnumMethod.name => IOSSslError.byName(map['code']) + }, message: map['message'], ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "code": code?.toNativeValue(), + "code": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => code?.toNativeValue(), + EnumMethod.value => code?.toValue(), + EnumMethod.name => code?.name() + }, "message": message, }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/ssl_error_type.dart b/flutter_inappwebview_platform_interface/lib/src/types/ssl_error_type.dart index b4db1bd57..a8348cdb3 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/ssl_error_type.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/ssl_error_type.dart @@ -32,7 +32,12 @@ class SslErrorType_ { apiName: 'SslError.SSL_EXPIRED', apiUrl: 'https://developer.android.com/reference/android/net/http/SslError#SSL_EXPIRED', - value: 1) + value: 1), + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_EXPIRED', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status', + value: 2) ]) static const EXPIRED = SslErrorType_._internal('EXPIRED'); @@ -82,7 +87,12 @@ class SslErrorType_ { apiName: 'SecTrustResultType.invalid', apiUrl: 'https://developer.apple.com/documentation/security/sectrustresulttype/invalid', - value: 0) + value: 0), + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_IS_INVALID', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status', + value: 5) ]) static const INVALID = SslErrorType_._internal('INVALID'); @@ -176,7 +186,9 @@ class SslErrorType_ { ///Indicates a failure other than that of trust evaluation. /// ///This value indicates that evaluation failed for some other reason. - ///This can be caused by either a revoked certificate or by OS-level errors that are unrelated to the certificates themselves. + /// + ///On iOS and macOS, this can be caused by either a revoked certificate or + ///by OS-level errors that are unrelated to the certificates themselves. @EnumSupportedPlatforms(platforms: [ EnumIOSPlatform( apiName: 'SecTrustResultType.otherError', @@ -187,9 +199,37 @@ class SslErrorType_ { apiName: 'SecTrustResultType.otherError', apiUrl: 'https://developer.apple.com/documentation/security/sectrustresulttype/othererror', - value: 7) + value: 7), + EnumWindowsPlatform( + apiName: + 'COREWEBVIEW2_WEB_ERROR_STATUS_CLIENT_CERTIFICATE_CONTAINS_ERRORS', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status', + value: 3) ]) static const OTHER_ERROR = SslErrorType_._internal('OTHER_ERROR'); + + ///Indicates that the SSL certificate common name does not match the web address. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: + 'COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_COMMON_NAME_IS_INCORRECT', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status', + value: 1) + ]) + static const COMMON_NAME_IS_INCORRECT = + SslErrorType_._internal('COMMON_NAME_IS_INCORRECT'); + + ///Indicates that the SSL certificate has been revoked. + @EnumSupportedPlatforms(platforms: [ + EnumWindowsPlatform( + apiName: 'COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_REVOKED', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status', + value: 4) + ]) + static const REVOKED = SslErrorType_._internal('REVOKED'); } ///Class that represents the Android-specific primary error associated to the server SSL certificate. diff --git a/flutter_inappwebview_platform_interface/lib/src/types/ssl_error_type.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/ssl_error_type.g.dart index e4043d9fc..de0aade1f 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/ssl_error_type.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/ssl_error_type.g.dart @@ -17,10 +17,25 @@ class SslErrorType { String value, Function nativeValue) => SslErrorType._internal(value, nativeValue()); + ///Indicates that the SSL certificate common name does not match the web address. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_COMMON_NAME_IS_INCORRECT](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status)) + static final COMMON_NAME_IS_INCORRECT = + SslErrorType._internalMultiPlatform('COMMON_NAME_IS_INCORRECT', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 1; + default: + break; + } + return null; + }); + ///The date of the certificate is invalid. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - SslError.DATE_INVALID](https://developer.android.com/reference/android/net/http/SslError#SSL_DATE_INVALID)) + ///- Android WebView ([Official API - SslError.DATE_INVALID](https://developer.android.com/reference/android/net/http/SslError#SSL_DATE_INVALID)) static final DATE_INVALID = SslErrorType._internalMultiPlatform('DATE_INVALID', () { switch (defaultTargetPlatform) { @@ -40,8 +55,8 @@ class SslErrorType { ///The Keychain Access utility refers to this value as "Never Trust." /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - SecTrustResultType.deny](https://developer.apple.com/documentation/security/sectrustresulttype/deny)) - ///- MacOS ([Official API - SecTrustResultType.deny](https://developer.apple.com/documentation/security/sectrustresulttype/deny)) + ///- iOS WKWebView ([Official API - SecTrustResultType.deny](https://developer.apple.com/documentation/security/sectrustresulttype/deny)) + ///- macOS WKWebView ([Official API - SecTrustResultType.deny](https://developer.apple.com/documentation/security/sectrustresulttype/deny)) static final DENY = SslErrorType._internalMultiPlatform('DENY', () { switch (defaultTargetPlatform) { case TargetPlatform.iOS: @@ -57,11 +72,14 @@ class SslErrorType { ///The certificate has expired. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - SslError.SSL_EXPIRED](https://developer.android.com/reference/android/net/http/SslError#SSL_EXPIRED)) + ///- Android WebView ([Official API - SslError.SSL_EXPIRED](https://developer.android.com/reference/android/net/http/SslError#SSL_EXPIRED)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_EXPIRED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status)) static final EXPIRED = SslErrorType._internalMultiPlatform('EXPIRED', () { switch (defaultTargetPlatform) { case TargetPlatform.android: return 1; + case TargetPlatform.windows: + return 2; default: break; } @@ -76,8 +94,8 @@ class SslErrorType { ///Changing parameter values and reevaluating is unlikely to succeed unless you provide different certificates. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - SecTrustResultType.fatalTrustFailure](https://developer.apple.com/documentation/security/sectrustresulttype/fataltrustfailure)) - ///- MacOS ([Official API - SecTrustResultType.fatalTrustFailure](https://developer.apple.com/documentation/security/sectrustresulttype/fataltrustfailure)) + ///- iOS WKWebView ([Official API - SecTrustResultType.fatalTrustFailure](https://developer.apple.com/documentation/security/sectrustresulttype/fataltrustfailure)) + ///- macOS WKWebView ([Official API - SecTrustResultType.fatalTrustFailure](https://developer.apple.com/documentation/security/sectrustresulttype/fataltrustfailure)) static final FATAL_TRUST_FAILURE = SslErrorType._internalMultiPlatform('FATAL_TRUST_FAILURE', () { switch (defaultTargetPlatform) { @@ -94,7 +112,7 @@ class SslErrorType { ///Hostname mismatch. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - SslError.SSL_IDMISMATCH](https://developer.android.com/reference/android/net/http/SslError#SSL_IDMISMATCH)) + ///- Android WebView ([Official API - SslError.SSL_IDMISMATCH](https://developer.android.com/reference/android/net/http/SslError#SSL_IDMISMATCH)) static final IDMISMATCH = SslErrorType._internalMultiPlatform('IDMISMATCH', () { switch (defaultTargetPlatform) { @@ -109,9 +127,10 @@ class SslErrorType { ///Indicates an invalid setting or result. A generic error occurred. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - SslError.SSL_INVALID](https://developer.android.com/reference/android/net/http/SslError#SSL_INVALID)) - ///- iOS ([Official API - SecTrustResultType.invalid](https://developer.apple.com/documentation/security/sectrustresulttype/invalid)) - ///- MacOS ([Official API - SecTrustResultType.invalid](https://developer.apple.com/documentation/security/sectrustresulttype/invalid)) + ///- Android WebView ([Official API - SslError.SSL_INVALID](https://developer.android.com/reference/android/net/http/SslError#SSL_INVALID)) + ///- iOS WKWebView ([Official API - SecTrustResultType.invalid](https://developer.apple.com/documentation/security/sectrustresulttype/invalid)) + ///- macOS WKWebView ([Official API - SecTrustResultType.invalid](https://developer.apple.com/documentation/security/sectrustresulttype/invalid)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_IS_INVALID](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status)) static final INVALID = SslErrorType._internalMultiPlatform('INVALID', () { switch (defaultTargetPlatform) { case TargetPlatform.android: @@ -120,6 +139,8 @@ class SslErrorType { return 0; case TargetPlatform.macOS: return 0; + case TargetPlatform.windows: + return 5; default: break; } @@ -129,7 +150,7 @@ class SslErrorType { ///The certificate is not yet valid. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - SslError.SSL_NOTYETVALID](https://developer.android.com/reference/android/net/http/SslError#SSL_NOTYETVALID)) + ///- Android WebView ([Official API - SslError.SSL_NOTYETVALID](https://developer.android.com/reference/android/net/http/SslError#SSL_NOTYETVALID)) static final NOT_YET_VALID = SslErrorType._internalMultiPlatform('NOT_YET_VALID', () { switch (defaultTargetPlatform) { @@ -144,11 +165,14 @@ class SslErrorType { ///Indicates a failure other than that of trust evaluation. /// ///This value indicates that evaluation failed for some other reason. - ///This can be caused by either a revoked certificate or by OS-level errors that are unrelated to the certificates themselves. + /// + ///On iOS and macOS, this can be caused by either a revoked certificate or + ///by OS-level errors that are unrelated to the certificates themselves. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - SecTrustResultType.otherError](https://developer.apple.com/documentation/security/sectrustresulttype/othererror)) - ///- MacOS ([Official API - SecTrustResultType.otherError](https://developer.apple.com/documentation/security/sectrustresulttype/othererror)) + ///- iOS WKWebView ([Official API - SecTrustResultType.otherError](https://developer.apple.com/documentation/security/sectrustresulttype/othererror)) + ///- macOS WKWebView ([Official API - SecTrustResultType.otherError](https://developer.apple.com/documentation/security/sectrustresulttype/othererror)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_CLIENT_CERTIFICATE_CONTAINS_ERRORS](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status)) static final OTHER_ERROR = SslErrorType._internalMultiPlatform('OTHER_ERROR', () { switch (defaultTargetPlatform) { @@ -156,6 +180,8 @@ class SslErrorType { return 7; case TargetPlatform.macOS: return 7; + case TargetPlatform.windows: + return 3; default: break; } @@ -173,8 +199,8 @@ class SslErrorType { ///you should check again using that date to see if the message was valid when you originally received it. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - SecTrustResultType.recoverableTrustFailure](https://developer.apple.com/documentation/security/sectrustresulttype/recoverabletrustfailure)) - ///- MacOS ([Official API - SecTrustResultType.recoverableTrustFailure](https://developer.apple.com/documentation/security/sectrustresulttype/recoverabletrustfailure)) + ///- iOS WKWebView ([Official API - SecTrustResultType.recoverableTrustFailure](https://developer.apple.com/documentation/security/sectrustresulttype/recoverabletrustfailure)) + ///- macOS WKWebView ([Official API - SecTrustResultType.recoverableTrustFailure](https://developer.apple.com/documentation/security/sectrustresulttype/recoverabletrustfailure)) static final RECOVERABLE_TRUST_FAILURE = SslErrorType._internalMultiPlatform('RECOVERABLE_TRUST_FAILURE', () { switch (defaultTargetPlatform) { @@ -188,6 +214,20 @@ class SslErrorType { return null; }); + ///Indicates that the SSL certificate has been revoked. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_REVOKED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#corewebview2_web_error_status)) + static final REVOKED = SslErrorType._internalMultiPlatform('REVOKED', () { + switch (defaultTargetPlatform) { + case TargetPlatform.windows: + return 4; + default: + break; + } + return null; + }); + ///Indicates the evaluation succeeded and the certificate is implicitly trusted, but user intent was not explicitly specified. /// ///This value indicates that evaluation reached an (implicitly trusted) anchor certificate without any evaluation failures, @@ -198,8 +238,8 @@ class SslErrorType { ///When receiving this value, most apps should trust the chain. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - SecTrustResultType.unspecified](https://developer.apple.com/documentation/security/sectrustresulttype/unspecified)) - ///- MacOS ([Official API - SecTrustResultType.unspecified](https://developer.apple.com/documentation/security/sectrustresulttype/unspecified)) + ///- iOS WKWebView ([Official API - SecTrustResultType.unspecified](https://developer.apple.com/documentation/security/sectrustresulttype/unspecified)) + ///- macOS WKWebView ([Official API - SecTrustResultType.unspecified](https://developer.apple.com/documentation/security/sectrustresulttype/unspecified)) static final UNSPECIFIED = SslErrorType._internalMultiPlatform('UNSPECIFIED', () { switch (defaultTargetPlatform) { @@ -216,7 +256,7 @@ class SslErrorType { ///The certificate authority is not trusted. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - SslError.SSL_UNTRUSTED](https://developer.android.com/reference/android/net/http/SslError#SSL_UNTRUSTED)) + ///- Android WebView ([Official API - SslError.SSL_UNTRUSTED](https://developer.android.com/reference/android/net/http/SslError#SSL_UNTRUSTED)) static final UNTRUSTED = SslErrorType._internalMultiPlatform('UNTRUSTED', () { switch (defaultTargetPlatform) { case TargetPlatform.android: @@ -229,6 +269,7 @@ class SslErrorType { ///Set of all values of [SslErrorType]. static final Set values = [ + SslErrorType.COMMON_NAME_IS_INCORRECT, SslErrorType.DATE_INVALID, SslErrorType.DENY, SslErrorType.EXPIRED, @@ -238,6 +279,7 @@ class SslErrorType { SslErrorType.NOT_YET_VALID, SslErrorType.OTHER_ERROR, SslErrorType.RECOVERABLE_TRUST_FAILURE, + SslErrorType.REVOKED, SslErrorType.UNSPECIFIED, SslErrorType.UNTRUSTED, ].toSet(); @@ -268,18 +310,85 @@ class SslErrorType { return null; } + /// Gets a possible [SslErrorType] instance value with name [name]. + /// + /// Goes through [SslErrorType.values] looking for a value with + /// name [name], as reported by [SslErrorType.name]. + /// Returns the first value with the given name, otherwise `null`. + static SslErrorType? byName(String? name) { + if (name != null) { + try { + return SslErrorType.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [SslErrorType] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in SslErrorType.values) value.name(): value + }; + ///Gets [String] value. String toValue() => _value; - ///Gets [int?] native value. + ///Gets [int] native value if supported by the current platform, otherwise `null`. int? toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'COMMON_NAME_IS_INCORRECT': + return 'COMMON_NAME_IS_INCORRECT'; + case 'DATE_INVALID': + return 'DATE_INVALID'; + case 'DENY': + return 'DENY'; + case 'EXPIRED': + return 'EXPIRED'; + case 'FATAL_TRUST_FAILURE': + return 'FATAL_TRUST_FAILURE'; + case 'IDMISMATCH': + return 'IDMISMATCH'; + case 'INVALID': + return 'INVALID'; + case 'NOT_YET_VALID': + return 'NOT_YET_VALID'; + case 'OTHER_ERROR': + return 'OTHER_ERROR'; + case 'RECOVERABLE_TRUST_FAILURE': + return 'RECOVERABLE_TRUST_FAILURE'; + case 'REVOKED': + return 'REVOKED'; + case 'UNSPECIFIED': + return 'UNSPECIFIED'; + case 'UNTRUSTED': + return 'UNTRUSTED'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + @override String toString() { return _value; @@ -353,20 +462,43 @@ class AndroidSslError { return null; } + /// Gets a possible [AndroidSslError] instance value with name [name]. + /// + /// Goes through [AndroidSslError.values] looking for a value with + /// name [name], as reported by [AndroidSslError.name]. + /// Returns the first value with the given name, otherwise `null`. + static AndroidSslError? byName(String? name) { + if (name != null) { + try { + return AndroidSslError.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [AndroidSslError] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in AndroidSslError.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 4: return 'SSL_DATE_INVALID'; @@ -383,6 +515,22 @@ class AndroidSslError { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } ///Class that represents the iOS-specific primary error associated to the server SSL certificate. @@ -451,20 +599,43 @@ class IOSSslError { return null; } + /// Gets a possible [IOSSslError] instance value with name [name]. + /// + /// Goes through [IOSSslError.values] looking for a value with + /// name [name], as reported by [IOSSslError.name]. + /// Returns the first value with the given name, otherwise `null`. + static IOSSslError? byName(String? name) { + if (name != null) { + try { + return IOSSslError.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [IOSSslError] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in IOSSslError.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 3: return 'DENY'; @@ -481,4 +652,20 @@ class IOSSslError { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/tracing_category.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/tracing_category.g.dart index 3487a1843..5d91e3476 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/tracing_category.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/tracing_category.g.dart @@ -87,20 +87,43 @@ class TracingCategory { return null; } + /// Gets a possible [TracingCategory] instance value with name [name]. + /// + /// Goes through [TracingCategory.values] looking for a value with + /// name [name], as reported by [TracingCategory.name]. + /// Returns the first value with the given name, otherwise `null`. + static TracingCategory? byName(String? name) { + if (name != null) { + try { + return TracingCategory.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [TracingCategory] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in TracingCategory.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 1: return 'CATEGORIES_ALL'; @@ -121,4 +144,20 @@ class TracingCategory { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/tracing_mode.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/tracing_mode.g.dart index 3552fe3d1..303d7c2ec 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/tracing_mode.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/tracing_mode.g.dart @@ -59,26 +59,65 @@ class TracingMode { return null; } + /// Gets a possible [TracingMode] instance value with name [name]. + /// + /// Goes through [TracingMode.values] looking for a value with + /// name [name], as reported by [TracingMode.name]. + /// Returns the first value with the given name, otherwise `null`. + static TracingMode? byName(String? name) { + if (name != null) { + try { + return TracingMode.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [TracingMode] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in TracingMode.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 1: + return 'RECORD_CONTINUOUSLY'; + case 0: + return 'RECORD_UNTIL_FULL'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { - switch (_value) { - case 1: - return 'RECORD_CONTINUOUSLY'; - case 0: - return 'RECORD_UNTIL_FULL'; - } - return _value.toString(); + return name(); } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_default_display_mode.dart b/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_default_display_mode.dart index ef160eebe..829b9b6bb 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_default_display_mode.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_default_display_mode.dart @@ -1,5 +1,6 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; +import 'enum_method.dart'; import 'trusted_web_activity_display_mode.dart'; part 'trusted_web_activity_default_display_mode.g.dart'; @@ -13,7 +14,7 @@ class TrustedWebActivityDefaultDisplayMode_ @ExchangeableObjectMethod(toMapMergeWith: true) // ignore: unused_element - Map _toMapMergeWith() { + Map _toMapMergeWith({EnumMethod? enumMethod}) { return {"type": _type}; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_default_display_mode.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_default_display_mode.g.dart index 395866eba..634cbd4f6 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_default_display_mode.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_default_display_mode.g.dart @@ -13,14 +13,14 @@ class TrustedWebActivityDefaultDisplayMode static final String _type = "DEFAULT_MODE"; TrustedWebActivityDefaultDisplayMode(); @ExchangeableObjectMethod(toMapMergeWith: true) - Map _toMapMergeWith() { + Map _toMapMergeWith({EnumMethod? enumMethod}) { return {"type": _type}; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - ..._toMapMergeWith(), + ..._toMapMergeWith(enumMethod: enumMethod), }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_display_mode.dart b/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_display_mode.dart index 2b7e54ab9..97405a532 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_display_mode.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_display_mode.dart @@ -1,5 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; +import 'enum_method.dart'; + part 'trusted_web_activity_display_mode.g.dart'; ///Class that represents display mode of a Trusted Web Activity. diff --git a/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_display_mode.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_display_mode.g.dart index 064073015..ed97b55be 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_display_mode.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_display_mode.g.dart @@ -11,7 +11,7 @@ abstract class TrustedWebActivityDisplayMode { TrustedWebActivityDisplayMode(); ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return {}; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_immersive_display_mode.dart b/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_immersive_display_mode.dart index ead2d1898..dbddaec14 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_immersive_display_mode.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_immersive_display_mode.dart @@ -2,6 +2,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_i import 'trusted_web_activity_display_mode.dart'; import 'layout_in_display_cutout_mode.dart'; +import 'enum_method.dart'; part 'trusted_web_activity_immersive_display_mode.g.dart'; @@ -35,7 +36,7 @@ class TrustedWebActivityImmersiveDisplayMode_ @ExchangeableObjectMethod(toMapMergeWith: true) // ignore: unused_element - Map _toMapMergeWith() { + Map _toMapMergeWith({EnumMethod? enumMethod}) { return {"type": _type}; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_immersive_display_mode.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_immersive_display_mode.g.dart index a5370c9eb..41c9f4b55 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_immersive_display_mode.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_immersive_display_mode.g.dart @@ -33,32 +33,52 @@ class TrustedWebActivityImmersiveDisplayMode ///Gets a possible [TrustedWebActivityImmersiveDisplayMode] instance from a [Map] value. static TrustedWebActivityImmersiveDisplayMode? fromMap( - Map? map) { + Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = TrustedWebActivityImmersiveDisplayMode( isSticky: map['isSticky'], - layoutInDisplayCutoutMode: + layoutInDisplayCutoutMode: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => AndroidLayoutInDisplayCutoutMode.fromNativeValue( map['displayCutoutMode']), + EnumMethod.value => + AndroidLayoutInDisplayCutoutMode.fromValue(map['displayCutoutMode']), + EnumMethod.name => + AndroidLayoutInDisplayCutoutMode.byName(map['displayCutoutMode']) + }, ); - instance.displayCutoutMode = - LayoutInDisplayCutoutMode.fromNativeValue(map['displayCutoutMode'])!; + if (map['displayCutoutMode'] != null) { + instance.displayCutoutMode = + switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + LayoutInDisplayCutoutMode.fromNativeValue(map['displayCutoutMode']), + EnumMethod.value => + LayoutInDisplayCutoutMode.fromValue(map['displayCutoutMode']), + EnumMethod.name => + LayoutInDisplayCutoutMode.byName(map['displayCutoutMode']) + }!; + } return instance; } @ExchangeableObjectMethod(toMapMergeWith: true) - Map _toMapMergeWith() { + Map _toMapMergeWith({EnumMethod? enumMethod}) { return {"type": _type}; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "displayCutoutMode": displayCutoutMode.toNativeValue(), + "displayCutoutMode": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => displayCutoutMode.toNativeValue(), + EnumMethod.value => displayCutoutMode.toValue(), + EnumMethod.name => displayCutoutMode.name() + }, "isSticky": isSticky, - ..._toMapMergeWith(), + ..._toMapMergeWith(enumMethod: enumMethod), }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_screen_orientation.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_screen_orientation.g.dart index 1d7c4676b..93976eac5 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_screen_orientation.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/trusted_web_activity_screen_orientation.g.dart @@ -104,20 +104,45 @@ class TrustedWebActivityScreenOrientation { return null; } + /// Gets a possible [TrustedWebActivityScreenOrientation] instance value with name [name]. + /// + /// Goes through [TrustedWebActivityScreenOrientation.values] looking for a value with + /// name [name], as reported by [TrustedWebActivityScreenOrientation.name]. + /// Returns the first value with the given name, otherwise `null`. + static TrustedWebActivityScreenOrientation? byName(String? name) { + if (name != null) { + try { + return TrustedWebActivityScreenOrientation.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [TrustedWebActivityScreenOrientation] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in TrustedWebActivityScreenOrientation.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 5: return 'ANY'; @@ -140,4 +165,20 @@ class TrustedWebActivityScreenOrientation { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/ui_event_attribution.dart b/flutter_inappwebview_platform_interface/lib/src/types/ui_event_attribution.dart index 31f16b6cb..79bb0af4c 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/ui_event_attribution.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/ui_event_attribution.dart @@ -1,6 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import '../web_uri.dart'; +import 'enum_method.dart'; part 'ui_event_attribution.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/ui_event_attribution.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/ui_event_attribution.g.dart index 3fda296e9..9b85f14ec 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/ui_event_attribution.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/ui_event_attribution.g.dart @@ -35,7 +35,8 @@ class UIEventAttribution { required this.purchaser}); ///Gets a possible [UIEventAttribution] instance from a [Map] value. - static UIEventAttribution? fromMap(Map? map) { + static UIEventAttribution? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -49,7 +50,7 @@ class UIEventAttribution { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "destinationURL": destinationURL.toString(), "purchaser": purchaser, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/ui_image.dart b/flutter_inappwebview_platform_interface/lib/src/types/ui_image.dart index bafb8a76f..7d6f74674 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/ui_image.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/ui_image.dart @@ -1,7 +1,8 @@ import 'dart:typed_data'; - import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; +import 'enum_method.dart'; + part 'ui_image.g.dart'; ///Class that represents an object that manages iOS and MacOS image data in your app. diff --git a/flutter_inappwebview_platform_interface/lib/src/types/ui_image.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/ui_image.g.dart index 3071d8a0d..dff760b06 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/ui_image.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/ui_image.g.dart @@ -24,15 +24,15 @@ class UIImage { ///The name of the system symbol image. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS 13.0+ - ///- MacOS 11.0+ + ///- iOS WKWebView 13.0+ + ///- macOS WKWebView 11.0+ String? systemName; UIImage({this.name, this.systemName, this.data}) { assert(this.name != null || this.systemName != null || this.data != null); } ///Gets a possible [UIImage] instance from a [Map] value. - static UIImage? fromMap(Map? map) { + static UIImage? fromMap(Map? map, {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -47,7 +47,7 @@ class UIImage { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "data": data, "name": name, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/underline_style.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/underline_style.g.dart index 3a0871bcf..8b4a5d06b 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/underline_style.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/underline_style.g.dart @@ -82,20 +82,43 @@ class UnderlineStyle { return null; } + /// Gets a possible [UnderlineStyle] instance value with name [name]. + /// + /// Goes through [UnderlineStyle.values] looking for a value with + /// name [name], as reported by [UnderlineStyle.name]. + /// Returns the first value with the given name, otherwise `null`. + static UnderlineStyle? byName(String? name) { + if (name != null) { + try { + return UnderlineStyle.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [UnderlineStyle] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in UnderlineStyle.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 32768: return 'BY_WORD'; @@ -118,6 +141,22 @@ class UnderlineStyle { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } ///An iOS-specific Class that represents the constants for the underline style and strikethrough style attribute keys. @@ -198,20 +237,44 @@ class IOSNSUnderlineStyle { return null; } + /// Gets a possible [IOSNSUnderlineStyle] instance value with name [name]. + /// + /// Goes through [IOSNSUnderlineStyle.values] looking for a value with + /// name [name], as reported by [IOSNSUnderlineStyle.name]. + /// Returns the first value with the given name, otherwise `null`. + static IOSNSUnderlineStyle? byName(String? name) { + if (name != null) { + try { + return IOSNSUnderlineStyle.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [IOSNSUnderlineStyle] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in IOSNSUnderlineStyle.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 32768: return 'BY_WORD'; @@ -234,4 +297,20 @@ class IOSNSUnderlineStyle { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/url_authentication_challenge.dart b/flutter_inappwebview_platform_interface/lib/src/types/url_authentication_challenge.dart index aefb1df06..1d2f73aef 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/url_authentication_challenge.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/url_authentication_challenge.dart @@ -1,6 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import 'url_protection_space.dart'; +import 'enum_method.dart'; part 'url_authentication_challenge.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/url_authentication_challenge.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/url_authentication_challenge.g.dart index e62ddc4c6..b0258fea6 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/url_authentication_challenge.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/url_authentication_challenge.g.dart @@ -14,21 +14,23 @@ class URLAuthenticationChallenge { URLAuthenticationChallenge({required this.protectionSpace}); ///Gets a possible [URLAuthenticationChallenge] instance from a [Map] value. - static URLAuthenticationChallenge? fromMap(Map? map) { + static URLAuthenticationChallenge? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = URLAuthenticationChallenge( protectionSpace: URLProtectionSpace.fromMap( - map['protectionSpace']?.cast())!, + map['protectionSpace']?.cast(), + enumMethod: enumMethod)!, ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "protectionSpace": protectionSpace.toMap(), + "protectionSpace": protectionSpace.toMap(enumMethod: enumMethod), }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/url_credential.dart b/flutter_inappwebview_platform_interface/lib/src/types/url_credential.dart index 0bb91451e..54eddc6dc 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/url_credential.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/url_credential.dart @@ -1,13 +1,14 @@ import 'dart:typed_data'; - import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import '../x509_certificate/x509_certificate.dart'; import 'url_credential_persistence.dart'; +import 'enum_method.dart'; part 'url_credential.g.dart'; -List? _certificatesDeserializer(dynamic value) { +List? _certificatesDeserializer(dynamic value, + {EnumMethod? enumMethod}) { List? certificates; if (value != null) { certificates = []; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/url_credential.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/url_credential.g.dart index 6a135cb0a..94fc317c7 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/url_credential.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/url_credential.g.dart @@ -12,8 +12,8 @@ class URLCredential { ///The intermediate certificates of the credential, if it is a client certificate credential. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS - ///- MacOS + ///- iOS WKWebView + ///- macOS WKWebView List? certificates; ///Use [certificates] instead. @@ -30,8 +30,8 @@ class URLCredential { ///The credential’s persistence setting. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS - ///- MacOS + ///- iOS WKWebView + ///- macOS WKWebView URLCredentialPersistence? persistence; ///The credential’s user name. @@ -50,28 +50,48 @@ class URLCredential { } ///Gets a possible [URLCredential] instance from a [Map] value. - static URLCredential? fromMap(Map? map) { + static URLCredential? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = URLCredential( - certificates: _certificatesDeserializer(map['certificates']), - iosCertificates: _certificatesDeserializer(map['certificates']), - iosPersistence: + certificates: _certificatesDeserializer(map['certificates'], + enumMethod: enumMethod), + iosCertificates: _certificatesDeserializer(map['certificates'], + enumMethod: enumMethod), + iosPersistence: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => IOSURLCredentialPersistence.fromNativeValue(map['persistence']), + EnumMethod.value => + IOSURLCredentialPersistence.fromValue(map['persistence']), + EnumMethod.name => + IOSURLCredentialPersistence.byName(map['persistence']) + }, password: map['password'], - persistence: URLCredentialPersistence.fromNativeValue(map['persistence']), + persistence: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + URLCredentialPersistence.fromNativeValue(map['persistence']), + EnumMethod.value => + URLCredentialPersistence.fromValue(map['persistence']), + EnumMethod.name => URLCredentialPersistence.byName(map['persistence']) + }, username: map['username'], ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "certificates": certificates?.map((e) => e.toMap()).toList(), + "certificates": + certificates?.map((e) => e.toMap(enumMethod: enumMethod)).toList(), "password": password, - "persistence": persistence?.toNativeValue(), + "persistence": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => persistence?.toNativeValue(), + EnumMethod.value => persistence?.toValue(), + EnumMethod.name => persistence?.name() + }, "username": username, }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/url_credential_persistence.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/url_credential_persistence.g.dart index 75b4d5535..14c60abdf 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/url_credential_persistence.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/url_credential_persistence.g.dart @@ -63,20 +63,44 @@ class URLCredentialPersistence { return null; } + /// Gets a possible [URLCredentialPersistence] instance value with name [name]. + /// + /// Goes through [URLCredentialPersistence.values] looking for a value with + /// name [name], as reported by [URLCredentialPersistence.name]. + /// Returns the first value with the given name, otherwise `null`. + static URLCredentialPersistence? byName(String? name) { + if (name != null) { + try { + return URLCredentialPersistence.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [URLCredentialPersistence] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in URLCredentialPersistence.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 1: return 'FOR_SESSION'; @@ -89,6 +113,22 @@ class URLCredentialPersistence { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } ///An iOS-specific class that represents the constants that specify how long the credential will be kept. @@ -150,20 +190,45 @@ class IOSURLCredentialPersistence { return null; } + /// Gets a possible [IOSURLCredentialPersistence] instance value with name [name]. + /// + /// Goes through [IOSURLCredentialPersistence.values] looking for a value with + /// name [name], as reported by [IOSURLCredentialPersistence.name]. + /// Returns the first value with the given name, otherwise `null`. + static IOSURLCredentialPersistence? byName(String? name) { + if (name != null) { + try { + return IOSURLCredentialPersistence.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [IOSURLCredentialPersistence] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in IOSURLCredentialPersistence.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 1: return 'FOR_SESSION'; @@ -176,4 +241,20 @@ class IOSURLCredentialPersistence { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space.dart b/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space.dart index 2e18696b3..a2fd0e721 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space.dart @@ -1,5 +1,4 @@ import 'dart:typed_data'; - import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import '../x509_certificate/x509_certificate.dart'; @@ -7,10 +6,12 @@ import 'url_protection_space_proxy_type.dart'; import 'url_protection_space_authentication_method.dart'; import 'ssl_error.dart'; import 'ssl_certificate.dart'; +import 'enum_method.dart'; part 'url_protection_space.g.dart'; -List? _distinguishedNamesDeserializer(dynamic value) { +List? _distinguishedNamesDeserializer(dynamic value, + {EnumMethod? enumMethod}) { List? distinguishedNames; if (value != null) { distinguishedNames = []; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space.g.dart index 9af49ce84..22d45cdae 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space.g.dart @@ -11,8 +11,8 @@ class URLProtectionSpace { ///The authentication method used by the receiver. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLProtectionSpace.authenticationMethod](https://developer.apple.com/documentation/foundation/urlprotectionspace/1415028-authenticationmethod)) - ///- MacOS ([Official API - URLProtectionSpace.authenticationMethod](https://developer.apple.com/documentation/foundation/urlprotectionspace/1415028-authenticationmethod)) + ///- iOS WKWebView ([Official API - URLProtectionSpace.authenticationMethod](https://developer.apple.com/documentation/foundation/urlprotectionspace/1415028-authenticationmethod)) + ///- macOS WKWebView ([Official API - URLProtectionSpace.authenticationMethod](https://developer.apple.com/documentation/foundation/urlprotectionspace/1415028-authenticationmethod)) URLProtectionSpaceAuthenticationMethod? authenticationMethod; ///The acceptable certificate-issuing authorities for client certificate authentication. @@ -20,8 +20,8 @@ class URLProtectionSpace { ///The returned issuing authorities are encoded with Distinguished Encoding Rules (DER). /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLProtectionSpace.distinguishedNames](https://developer.apple.com/documentation/foundation/urlprotectionspace/1417061-distinguishednames)) - ///- MacOS ([Official API - URLProtectionSpace.distinguishedNames](https://developer.apple.com/documentation/foundation/urlprotectionspace/1417061-distinguishednames)) + ///- iOS WKWebView ([Official API - URLProtectionSpace.distinguishedNames](https://developer.apple.com/documentation/foundation/urlprotectionspace/1417061-distinguishednames)) + ///- macOS WKWebView ([Official API - URLProtectionSpace.distinguishedNames](https://developer.apple.com/documentation/foundation/urlprotectionspace/1417061-distinguishednames)) List? distinguishedNames; ///The hostname of the server. @@ -54,8 +54,8 @@ class URLProtectionSpace { ///The supported proxy types are listed in [URLProtectionSpaceProxyType.values]. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLProtectionSpace.proxyType](https://developer.apple.com/documentation/foundation/urlprotectionspace/1411924-proxytype)) - ///- MacOS ([Official API - URLProtectionSpace.proxyType](https://developer.apple.com/documentation/foundation/urlprotectionspace/1411924-proxytype)) + ///- iOS WKWebView ([Official API - URLProtectionSpace.proxyType](https://developer.apple.com/documentation/foundation/urlprotectionspace/1411924-proxytype)) + ///- macOS WKWebView ([Official API - URLProtectionSpace.proxyType](https://developer.apple.com/documentation/foundation/urlprotectionspace/1411924-proxytype)) URLProtectionSpaceProxyType? proxyType; ///A string indicating a protocol-specific subdivision of a single host. @@ -67,8 +67,8 @@ class URLProtectionSpace { ///This value is `true` if the credentials for the protection space represented by the receiver can be sent securely, `false` otherwise. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLProtectionSpace.receivesCredentialSecurely](https://developer.apple.com/documentation/foundation/urlprotectionspace/1415176-receivescredentialsecurely)) - ///- MacOS ([Official API - URLProtectionSpace.receivesCredentialSecurely](https://developer.apple.com/documentation/foundation/urlprotectionspace/1415176-receivescredentialsecurely)) + ///- iOS WKWebView ([Official API - URLProtectionSpace.receivesCredentialSecurely](https://developer.apple.com/documentation/foundation/urlprotectionspace/1415176-receivescredentialsecurely)) + ///- macOS WKWebView ([Official API - URLProtectionSpace.receivesCredentialSecurely](https://developer.apple.com/documentation/foundation/urlprotectionspace/1415176-receivescredentialsecurely)) bool? receivesCredentialSecurely; ///The SSL certificate used. @@ -105,50 +105,90 @@ class URLProtectionSpace { } ///Gets a possible [URLProtectionSpace] instance from a [Map] value. - static URLProtectionSpace? fromMap(Map? map) { + static URLProtectionSpace? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = URLProtectionSpace( - authenticationMethod: + authenticationMethod: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => URLProtectionSpaceAuthenticationMethod.fromNativeValue( map['authenticationMethod']), - distinguishedNames: - _distinguishedNamesDeserializer(map['distinguishedNames']), + EnumMethod.value => URLProtectionSpaceAuthenticationMethod.fromValue( + map['authenticationMethod']), + EnumMethod.name => URLProtectionSpaceAuthenticationMethod.byName( + map['authenticationMethod']) + }, + distinguishedNames: _distinguishedNamesDeserializer( + map['distinguishedNames'], + enumMethod: enumMethod), host: map['host'], - iosAuthenticationMethod: + iosAuthenticationMethod: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => IOSNSURLProtectionSpaceAuthenticationMethod.fromNativeValue( map['authenticationMethod']), - iosDistinguishedNames: - _distinguishedNamesDeserializer(map['distinguishedNames']), - iosProxyType: + EnumMethod.value => + IOSNSURLProtectionSpaceAuthenticationMethod.fromValue( + map['authenticationMethod']), + EnumMethod.name => IOSNSURLProtectionSpaceAuthenticationMethod.byName( + map['authenticationMethod']) + }, + iosDistinguishedNames: _distinguishedNamesDeserializer( + map['distinguishedNames'], + enumMethod: enumMethod), + iosProxyType: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => IOSNSURLProtectionSpaceProxyType.fromNativeValue(map['proxyType']), + EnumMethod.value => + IOSNSURLProtectionSpaceProxyType.fromValue(map['proxyType']), + EnumMethod.name => + IOSNSURLProtectionSpaceProxyType.byName(map['proxyType']) + }, iosReceivesCredentialSecurely: map['receivesCredentialSecurely'], port: map['port'], protocol: map['protocol'], - proxyType: URLProtectionSpaceProxyType.fromNativeValue(map['proxyType']), + proxyType: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + URLProtectionSpaceProxyType.fromNativeValue(map['proxyType']), + EnumMethod.value => + URLProtectionSpaceProxyType.fromValue(map['proxyType']), + EnumMethod.name => URLProtectionSpaceProxyType.byName(map['proxyType']) + }, realm: map['realm'], receivesCredentialSecurely: map['receivesCredentialSecurely'], sslCertificate: SslCertificate.fromMap( - map['sslCertificate']?.cast()), - sslError: SslError.fromMap(map['sslError']?.cast()), + map['sslCertificate']?.cast(), + enumMethod: enumMethod), + sslError: SslError.fromMap(map['sslError']?.cast(), + enumMethod: enumMethod), ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "authenticationMethod": authenticationMethod?.toNativeValue(), - "distinguishedNames": distinguishedNames?.map((e) => e.toMap()).toList(), + "authenticationMethod": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => authenticationMethod?.toNativeValue(), + EnumMethod.value => authenticationMethod?.toValue(), + EnumMethod.name => authenticationMethod?.name() + }, + "distinguishedNames": distinguishedNames + ?.map((e) => e.toMap(enumMethod: enumMethod)) + .toList(), "host": host, "port": port, "protocol": protocol, - "proxyType": proxyType?.toNativeValue(), + "proxyType": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => proxyType?.toNativeValue(), + EnumMethod.value => proxyType?.toValue(), + EnumMethod.name => proxyType?.name() + }, "realm": realm, "receivesCredentialSecurely": receivesCredentialSecurely, - "sslCertificate": sslCertificate?.toMap(), - "sslError": sslError?.toMap(), + "sslCertificate": sslCertificate?.toMap(enumMethod: enumMethod), + "sslError": sslError?.toMap(enumMethod: enumMethod), }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space_authentication_method.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space_authentication_method.g.dart index a8f318ead..17e96fb4c 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space_authentication_method.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space_authentication_method.g.dart @@ -78,18 +78,69 @@ class URLProtectionSpaceAuthenticationMethod { return null; } + /// Gets a possible [URLProtectionSpaceAuthenticationMethod] instance value with name [name]. + /// + /// Goes through [URLProtectionSpaceAuthenticationMethod.values] looking for a value with + /// name [name], as reported by [URLProtectionSpaceAuthenticationMethod.name]. + /// Returns the first value with the given name, otherwise `null`. + static URLProtectionSpaceAuthenticationMethod? byName(String? name) { + if (name != null) { + try { + return URLProtectionSpaceAuthenticationMethod.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [URLProtectionSpaceAuthenticationMethod] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in URLProtectionSpaceAuthenticationMethod.values) + value.name(): value + }; + ///Gets [String] value. String toValue() => _value; ///Gets [String] native value. String toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'NSURLAuthenticationMethodClientCertificate': + return 'NSURL_AUTHENTICATION_METHOD_CLIENT_CERTIFICATE'; + case 'NSURLAuthenticationMethodNegotiate': + return 'NSURL_AUTHENTICATION_METHOD_NEGOTIATE'; + case 'NSURLAuthenticationMethodNTLM': + return 'NSURL_AUTHENTICATION_METHOD_NTLM'; + case 'NSURLAuthenticationMethodServerTrust': + return 'NSURL_AUTHENTICATION_METHOD_SERVER_TRUST'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { return _value; @@ -172,18 +223,69 @@ class IOSNSURLProtectionSpaceAuthenticationMethod { return null; } + /// Gets a possible [IOSNSURLProtectionSpaceAuthenticationMethod] instance value with name [name]. + /// + /// Goes through [IOSNSURLProtectionSpaceAuthenticationMethod.values] looking for a value with + /// name [name], as reported by [IOSNSURLProtectionSpaceAuthenticationMethod.name]. + /// Returns the first value with the given name, otherwise `null`. + static IOSNSURLProtectionSpaceAuthenticationMethod? byName(String? name) { + if (name != null) { + try { + return IOSNSURLProtectionSpaceAuthenticationMethod.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [IOSNSURLProtectionSpaceAuthenticationMethod] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in IOSNSURLProtectionSpaceAuthenticationMethod.values) + value.name(): value + }; + ///Gets [String] value. String toValue() => _value; ///Gets [String] native value. String toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'NSURLAuthenticationMethodClientCertificate': + return 'NSURL_AUTHENTICATION_METHOD_CLIENT_CERTIFICATE'; + case 'NSURLAuthenticationMethodNegotiate': + return 'NSURL_AUTHENTICATION_METHOD_NEGOTIATE'; + case 'NSURLAuthenticationMethodNTLM': + return 'NSURL_AUTHENTICATION_METHOD_NTLM'; + case 'NSURLAuthenticationMethodServerTrust': + return 'NSURL_AUTHENTICATION_METHOD_SERVER_TRUST'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { return _value; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space_http_auth_credentials.dart b/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space_http_auth_credentials.dart index b5a67de50..6ca648247 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space_http_auth_credentials.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space_http_auth_credentials.dart @@ -3,6 +3,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_i import 'url_protection_space.dart'; import 'url_credential.dart'; import '../platform_http_auth_credentials_database.dart'; +import 'enum_method.dart'; part 'url_protection_space_http_auth_credentials.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space_http_auth_credentials.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space_http_auth_credentials.g.dart index 744177cb3..9f1ec6d93 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space_http_auth_credentials.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space_http_auth_credentials.g.dart @@ -19,26 +19,30 @@ class URLProtectionSpaceHttpAuthCredentials { ///Gets a possible [URLProtectionSpaceHttpAuthCredentials] instance from a [Map] value. static URLProtectionSpaceHttpAuthCredentials? fromMap( - Map? map) { + Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = URLProtectionSpaceHttpAuthCredentials( credentials: map['credentials'] != null - ? List.from(map['credentials'] - .map((e) => URLCredential.fromMap(e?.cast())!)) + ? List.from(map['credentials'].map((e) => + URLCredential.fromMap(e?.cast(), + enumMethod: enumMethod)!)) : null, protectionSpace: URLProtectionSpace.fromMap( - map['protectionSpace']?.cast()), + map['protectionSpace']?.cast(), + enumMethod: enumMethod), ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "credentials": credentials?.map((e) => e.toMap()).toList(), - "protectionSpace": protectionSpace?.toMap(), + "credentials": + credentials?.map((e) => e.toMap(enumMethod: enumMethod)).toList(), + "protectionSpace": protectionSpace?.toMap(enumMethod: enumMethod), }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space_proxy_type.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space_proxy_type.g.dart index e174e5823..740c8f6e0 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space_proxy_type.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/url_protection_space_proxy_type.g.dart @@ -70,18 +70,69 @@ class URLProtectionSpaceProxyType { return null; } + /// Gets a possible [URLProtectionSpaceProxyType] instance value with name [name]. + /// + /// Goes through [URLProtectionSpaceProxyType.values] looking for a value with + /// name [name], as reported by [URLProtectionSpaceProxyType.name]. + /// Returns the first value with the given name, otherwise `null`. + static URLProtectionSpaceProxyType? byName(String? name) { + if (name != null) { + try { + return URLProtectionSpaceProxyType.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [URLProtectionSpaceProxyType] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in URLProtectionSpaceProxyType.values) + value.name(): value + }; + ///Gets [String] value. String toValue() => _value; ///Gets [String] native value. String toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'NSURLProtectionSpaceFTPProxy': + return 'URL_PROTECTION_SPACE_FTP_PROXY'; + case 'NSURLProtectionSpaceHTTPSProxy': + return 'URL_PROTECTION_SPACE_HTTPS_PROXY'; + case 'NSURLProtectionSpaceHTTPProxy': + return 'URL_PROTECTION_SPACE_HTTP_PROXY'; + case 'NSURLProtectionSpaceSOCKSProxy': + return 'URL_PROTECTION_SPACE_SOCKS_PROXY'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { return _value; @@ -155,18 +206,69 @@ class IOSNSURLProtectionSpaceProxyType { return null; } + /// Gets a possible [IOSNSURLProtectionSpaceProxyType] instance value with name [name]. + /// + /// Goes through [IOSNSURLProtectionSpaceProxyType.values] looking for a value with + /// name [name], as reported by [IOSNSURLProtectionSpaceProxyType.name]. + /// Returns the first value with the given name, otherwise `null`. + static IOSNSURLProtectionSpaceProxyType? byName(String? name) { + if (name != null) { + try { + return IOSNSURLProtectionSpaceProxyType.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [IOSNSURLProtectionSpaceProxyType] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in IOSNSURLProtectionSpaceProxyType.values) + value.name(): value + }; + ///Gets [String] value. String toValue() => _value; ///Gets [String] native value. String toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'NSURLProtectionSpaceFTPProxy': + return 'NSURL_PROTECTION_SPACE_FTP_PROXY'; + case 'NSURLProtectionSpaceHTTPSProxy': + return 'NSURL_PROTECTION_SPACE_HTTPS_PROXY'; + case 'NSURLProtectionSpaceSOCKSProxy': + return 'NSURL_PROTECTION_SPACE_SOCKS_PROXY'; + case 'NSURLProtectionSpaceHTTPProxy': + return 'NSUR_PROTECTION_SPACE_HTTP_PROXY'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { return _value; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/url_request.dart b/flutter_inappwebview_platform_interface/lib/src/types/url_request.dart index e737a6f7e..ed66b6dc9 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/url_request.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/url_request.dart @@ -5,6 +5,7 @@ import '../web_uri.dart'; import 'url_request_cache_policy.dart'; import 'url_request_network_service_type.dart'; import 'url_request_attribution.dart'; +import 'enum_method.dart'; part 'url_request.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/url_request.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/url_request.g.dart index e938c53b4..271fd46b1 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/url_request.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/url_request.g.dart @@ -11,22 +11,22 @@ class URLRequest { ///A Boolean value indicating whether the request is allowed to use the built-in cellular radios to satisfy the request. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLRequest.allowsCellularAccess](https://developer.apple.com/documentation/foundation/urlrequest/2011607-allowscellularaccess/)) - ///- MacOS ([Official API - URLRequest.allowsCellularAccess](https://developer.apple.com/documentation/foundation/urlrequest/2011607-allowscellularaccess/)) + ///- iOS WKWebView ([Official API - URLRequest.allowsCellularAccess](https://developer.apple.com/documentation/foundation/urlrequest/2011607-allowscellularaccess/)) + ///- macOS WKWebView ([Official API - URLRequest.allowsCellularAccess](https://developer.apple.com/documentation/foundation/urlrequest/2011607-allowscellularaccess/)) bool? allowsCellularAccess; ///A Boolean value that indicates whether the request may use the network when the user has specified Low Data Mode. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS 13.0+ ([Official API - URLRequest.allowsConstrainedNetworkAccess](https://developer.apple.com/documentation/foundation/urlrequest/3358304-allowsconstrainednetworkaccess)) - ///- MacOS 10.15+ ([Official API - URLRequest.allowsConstrainedNetworkAccess](https://developer.apple.com/documentation/foundation/urlrequest/3358304-allowsconstrainednetworkaccess)) + ///- iOS WKWebView 13.0+ ([Official API - URLRequest.allowsConstrainedNetworkAccess](https://developer.apple.com/documentation/foundation/urlrequest/3358304-allowsconstrainednetworkaccess)) + ///- macOS WKWebView 10.15+ ([Official API - URLRequest.allowsConstrainedNetworkAccess](https://developer.apple.com/documentation/foundation/urlrequest/3358304-allowsconstrainednetworkaccess)) bool? allowsConstrainedNetworkAccess; ///A Boolean value that indicates whether connections may use a network interface that the system considers expensive. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS 13.0+ ([Official API - URLRequest.allowsExpensiveNetworkAccess](https://developer.apple.com/documentation/foundation/urlrequest/3358305-allowsexpensivenetworkaccess)) - ///- MacOS 10.15+ ([Official API - URLRequest.allowsExpensiveNetworkAccess](https://developer.apple.com/documentation/foundation/urlrequest/3358305-allowsexpensivenetworkaccess)) + ///- iOS WKWebView 13.0+ ([Official API - URLRequest.allowsExpensiveNetworkAccess](https://developer.apple.com/documentation/foundation/urlrequest/3358305-allowsexpensivenetworkaccess)) + ///- macOS WKWebView 10.15+ ([Official API - URLRequest.allowsExpensiveNetworkAccess](https://developer.apple.com/documentation/foundation/urlrequest/3358305-allowsexpensivenetworkaccess)) bool? allowsExpensiveNetworkAccess; ///`true` if server endpoint is known to support HTTP/3. Enables QUIC racing @@ -34,8 +34,8 @@ class URLRequest { ///The default may be `true` in a future OS update. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS 14.5+ ([Official API - URLRequest.assumesHTTP3Capable](https://developer.apple.com/documentation/foundation/urlrequest/3738175-assumeshttp3capable)) - ///- MacOS 11.3+ ([Official API - URLRequest.assumesHTTP3Capable](https://developer.apple.com/documentation/foundation/urlrequest/3738175-assumeshttp3capable)) + ///- iOS WKWebView 14.5+ ([Official API - URLRequest.assumesHTTP3Capable](https://developer.apple.com/documentation/foundation/urlrequest/3738175-assumeshttp3capable)) + ///- macOS WKWebView 11.3+ ([Official API - URLRequest.assumesHTTP3Capable](https://developer.apple.com/documentation/foundation/urlrequest/3738175-assumeshttp3capable)) bool? assumesHTTP3Capable; ///The entities that can make a network request. @@ -43,8 +43,8 @@ class URLRequest { ///If you don’t set a value, the system assumes [URLRequestAttribution.DEVELOPER]. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS 15.0+ ([Official API - URLRequest.attribution](https://developer.apple.com/documentation/foundation/urlrequest/3767318-attribution)) - ///- MacOS 12.0+ ([Official API - URLRequest.attribution](https://developer.apple.com/documentation/foundation/urlrequest/3767318-attribution)) + ///- iOS WKWebView 15.0+ ([Official API - URLRequest.attribution](https://developer.apple.com/documentation/foundation/urlrequest/3767318-attribution)) + ///- macOS WKWebView 12.0+ ([Official API - URLRequest.attribution](https://developer.apple.com/documentation/foundation/urlrequest/3767318-attribution)) URLRequestAttribution? attribution; ///The data sent as the message body of a request, such as for an HTTP POST request. @@ -53,8 +53,8 @@ class URLRequest { ///The request’s cache policy. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLRequest.cachePolicy](https://developer.apple.com/documentation/foundation/urlrequest/2011593-cachepolicy)) - ///- MacOS ([Official API - URLRequest.cachePolicy](https://developer.apple.com/documentation/foundation/urlrequest/2011593-cachepolicy)) + ///- iOS WKWebView ([Official API - URLRequest.cachePolicy](https://developer.apple.com/documentation/foundation/urlrequest/2011593-cachepolicy)) + ///- macOS WKWebView ([Official API - URLRequest.cachePolicy](https://developer.apple.com/documentation/foundation/urlrequest/2011593-cachepolicy)) URLRequestCachePolicy? cachePolicy; ///A dictionary containing all of the HTTP header fields for a request. @@ -63,15 +63,15 @@ class URLRequest { ///A Boolean value indicating whether cookies will be sent with and set for this request. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLRequest.httpShouldHandleCookies](https://developer.apple.com/documentation/foundation/urlrequest/2011548-httpshouldhandlecookies)) - ///- MacOS ([Official API - URLRequest.httpShouldHandleCookies](https://developer.apple.com/documentation/foundation/urlrequest/2011548-httpshouldhandlecookies)) + ///- iOS WKWebView ([Official API - URLRequest.httpShouldHandleCookies](https://developer.apple.com/documentation/foundation/urlrequest/2011548-httpshouldhandlecookies)) + ///- macOS WKWebView ([Official API - URLRequest.httpShouldHandleCookies](https://developer.apple.com/documentation/foundation/urlrequest/2011548-httpshouldhandlecookies)) bool? httpShouldHandleCookies; ///A Boolean value indicating whether the request should transmit before the previous response is received. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLRequest.httpShouldUsePipelining](https://developer.apple.com/documentation/foundation/urlrequest/2011508-httpshouldusepipelining)) - ///- MacOS ([Official API - URLRequest.httpShouldUsePipelining](https://developer.apple.com/documentation/foundation/urlrequest/2011508-httpshouldusepipelining)) + ///- iOS WKWebView ([Official API - URLRequest.httpShouldUsePipelining](https://developer.apple.com/documentation/foundation/urlrequest/2011508-httpshouldusepipelining)) + ///- macOS WKWebView ([Official API - URLRequest.httpShouldUsePipelining](https://developer.apple.com/documentation/foundation/urlrequest/2011508-httpshouldusepipelining)) bool? httpShouldUsePipelining; ///Use [allowsCellularAccess] instead. @@ -114,8 +114,8 @@ class URLRequest { ///This URL is used for the cookie “same domain as main document” policy. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLRequest.mainDocumentURL](https://developer.apple.com/documentation/foundation/urlrequest/2011552-maindocumenturl)) - ///- MacOS ([Official API - URLRequest.mainDocumentURL](https://developer.apple.com/documentation/foundation/urlrequest/2011552-maindocumenturl)) + ///- iOS WKWebView ([Official API - URLRequest.mainDocumentURL](https://developer.apple.com/documentation/foundation/urlrequest/2011552-maindocumenturl)) + ///- macOS WKWebView ([Official API - URLRequest.mainDocumentURL](https://developer.apple.com/documentation/foundation/urlrequest/2011552-maindocumenturl)) WebUri? mainDocumentURL; ///The HTTP request method. @@ -126,15 +126,15 @@ class URLRequest { ///The service type associated with this request. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLRequest.networkServiceType](https://developer.apple.com/documentation/foundation/urlrequest/2011409-networkservicetype)) - ///- MacOS ([Official API - URLRequest.networkServiceType](https://developer.apple.com/documentation/foundation/urlrequest/2011409-networkservicetype)) + ///- iOS WKWebView ([Official API - URLRequest.networkServiceType](https://developer.apple.com/documentation/foundation/urlrequest/2011409-networkservicetype)) + ///- macOS WKWebView ([Official API - URLRequest.networkServiceType](https://developer.apple.com/documentation/foundation/urlrequest/2011409-networkservicetype)) URLRequestNetworkServiceType? networkServiceType; ///The timeout interval of the request. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLRequest.timeoutInterval](https://developer.apple.com/documentation/foundation/urlrequest/2011509-timeoutinterval)) - ///- MacOS ([Official API - URLRequest.timeoutInterval](https://developer.apple.com/documentation/foundation/urlrequest/2011509-timeoutinterval)) + ///- iOS WKWebView ([Official API - URLRequest.timeoutInterval](https://developer.apple.com/documentation/foundation/urlrequest/2011509-timeoutinterval)) + ///- macOS WKWebView ([Official API - URLRequest.timeoutInterval](https://developer.apple.com/documentation/foundation/urlrequest/2011509-timeoutinterval)) double? timeoutInterval; ///The URL of the request. Setting this to `null` will load `about:blank`. @@ -189,7 +189,8 @@ class URLRequest { } ///Gets a possible [URLRequest] instance from a [Map] value. - static URLRequest? fromMap(Map? map) { + static URLRequest? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -198,33 +199,61 @@ class URLRequest { allowsConstrainedNetworkAccess: map['allowsConstrainedNetworkAccess'], allowsExpensiveNetworkAccess: map['allowsExpensiveNetworkAccess'], assumesHTTP3Capable: map['assumesHTTP3Capable'], - attribution: URLRequestAttribution.fromNativeValue(map['attribution']), + attribution: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + URLRequestAttribution.fromNativeValue(map['attribution']), + EnumMethod.value => URLRequestAttribution.fromValue(map['attribution']), + EnumMethod.name => URLRequestAttribution.byName(map['attribution']) + }, body: map['body'] != null ? Uint8List.fromList(map['body'].cast()) : null, - cachePolicy: URLRequestCachePolicy.fromNativeValue(map['cachePolicy']), + cachePolicy: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + URLRequestCachePolicy.fromNativeValue(map['cachePolicy']), + EnumMethod.value => URLRequestCachePolicy.fromValue(map['cachePolicy']), + EnumMethod.name => URLRequestCachePolicy.byName(map['cachePolicy']) + }, headers: map['headers']?.cast(), httpShouldHandleCookies: map['httpShouldHandleCookies'], httpShouldUsePipelining: map['httpShouldUsePipelining'], iosAllowsCellularAccess: map['allowsCellularAccess'], iosAllowsConstrainedNetworkAccess: map['allowsConstrainedNetworkAccess'], iosAllowsExpensiveNetworkAccess: map['allowsExpensiveNetworkAccess'], - iosCachePolicy: + iosCachePolicy: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => IOSURLRequestCachePolicy.fromNativeValue(map['cachePolicy']), + EnumMethod.value => + IOSURLRequestCachePolicy.fromValue(map['cachePolicy']), + EnumMethod.name => IOSURLRequestCachePolicy.byName(map['cachePolicy']) + }, iosHttpShouldHandleCookies: map['httpShouldHandleCookies'], iosHttpShouldUsePipelining: map['httpShouldUsePipelining'], iosMainDocumentURL: map['mainDocumentURL'] != null ? Uri.tryParse(map['mainDocumentURL']) : null, - iosNetworkServiceType: IOSURLRequestNetworkServiceType.fromNativeValue( - map['networkServiceType']), + iosNetworkServiceType: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + IOSURLRequestNetworkServiceType.fromNativeValue( + map['networkServiceType']), + EnumMethod.value => + IOSURLRequestNetworkServiceType.fromValue(map['networkServiceType']), + EnumMethod.name => + IOSURLRequestNetworkServiceType.byName(map['networkServiceType']) + }, iosTimeoutInterval: map['timeoutInterval'], mainDocumentURL: map['mainDocumentURL'] != null ? WebUri(map['mainDocumentURL']) : null, method: map['method'], - networkServiceType: URLRequestNetworkServiceType.fromNativeValue( - map['networkServiceType']), + networkServiceType: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => URLRequestNetworkServiceType.fromNativeValue( + map['networkServiceType']), + EnumMethod.value => + URLRequestNetworkServiceType.fromValue(map['networkServiceType']), + EnumMethod.name => + URLRequestNetworkServiceType.byName(map['networkServiceType']) + }, timeoutInterval: map['timeoutInterval'], url: map['url'] != null ? WebUri(map['url']) : null, ); @@ -232,21 +261,33 @@ class URLRequest { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "allowsCellularAccess": allowsCellularAccess, "allowsConstrainedNetworkAccess": allowsConstrainedNetworkAccess, "allowsExpensiveNetworkAccess": allowsExpensiveNetworkAccess, "assumesHTTP3Capable": assumesHTTP3Capable, - "attribution": attribution?.toNativeValue(), + "attribution": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => attribution?.toNativeValue(), + EnumMethod.value => attribution?.toValue(), + EnumMethod.name => attribution?.name() + }, "body": body, - "cachePolicy": cachePolicy?.toNativeValue(), + "cachePolicy": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => cachePolicy?.toNativeValue(), + EnumMethod.value => cachePolicy?.toValue(), + EnumMethod.name => cachePolicy?.name() + }, "headers": headers, "httpShouldHandleCookies": httpShouldHandleCookies, "httpShouldUsePipelining": httpShouldUsePipelining, "mainDocumentURL": mainDocumentURL?.toString(), "method": method, - "networkServiceType": networkServiceType?.toNativeValue(), + "networkServiceType": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => networkServiceType?.toNativeValue(), + EnumMethod.value => networkServiceType?.toValue(), + EnumMethod.name => networkServiceType?.name() + }, "timeoutInterval": timeoutInterval, "url": url?.toString(), }; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/url_request_attribution.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/url_request_attribution.g.dart index e40c4545f..6fab9a089 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/url_request_attribution.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/url_request_attribution.g.dart @@ -60,26 +60,66 @@ class URLRequestAttribution { return null; } + /// Gets a possible [URLRequestAttribution] instance value with name [name]. + /// + /// Goes through [URLRequestAttribution.values] looking for a value with + /// name [name], as reported by [URLRequestAttribution.name]. + /// Returns the first value with the given name, otherwise `null`. + static URLRequestAttribution? byName(String? name) { + if (name != null) { + try { + return URLRequestAttribution.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [URLRequestAttribution] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in URLRequestAttribution.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 0: + return 'DEVELOPER'; + case 1: + return 'USER'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { - switch (_value) { - case 0: - return 'DEVELOPER'; - case 1: - return 'USER'; - } - return _value.toString(); + return name(); } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/url_request_cache_policy.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/url_request_cache_policy.g.dart index 8424682f8..c9bf1de3d 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/url_request_cache_policy.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/url_request_cache_policy.g.dart @@ -88,20 +88,44 @@ class URLRequestCachePolicy { return null; } + /// Gets a possible [URLRequestCachePolicy] instance value with name [name]. + /// + /// Goes through [URLRequestCachePolicy.values] looking for a value with + /// name [name], as reported by [URLRequestCachePolicy.name]. + /// Returns the first value with the given name, otherwise `null`. + static URLRequestCachePolicy? byName(String? name) { + if (name != null) { + try { + return URLRequestCachePolicy.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [URLRequestCachePolicy] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in URLRequestCachePolicy.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 4: return 'RELOAD_IGNORING_LOCAL_AND_REMOTE_CACHE_DATA'; @@ -118,6 +142,22 @@ class URLRequestCachePolicy { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } ///An iOS-specific Class that represents the constants used to specify interaction with the cached responses. @@ -204,20 +244,44 @@ class IOSURLRequestCachePolicy { return null; } + /// Gets a possible [IOSURLRequestCachePolicy] instance value with name [name]. + /// + /// Goes through [IOSURLRequestCachePolicy.values] looking for a value with + /// name [name], as reported by [IOSURLRequestCachePolicy.name]. + /// Returns the first value with the given name, otherwise `null`. + static IOSURLRequestCachePolicy? byName(String? name) { + if (name != null) { + try { + return IOSURLRequestCachePolicy.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [IOSURLRequestCachePolicy] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in IOSURLRequestCachePolicy.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 4: return 'RELOAD_IGNORING_LOCAL_AND_REMOTE_CACHE_DATA'; @@ -234,4 +298,20 @@ class IOSURLRequestCachePolicy { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/url_request_network_service_type.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/url_request_network_service_type.g.dart index 7e9d6d3dc..4f3e0db03 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/url_request_network_service_type.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/url_request_network_service_type.g.dart @@ -85,20 +85,45 @@ class URLRequestNetworkServiceType { return null; } + /// Gets a possible [URLRequestNetworkServiceType] instance value with name [name]. + /// + /// Goes through [URLRequestNetworkServiceType.values] looking for a value with + /// name [name], as reported by [URLRequestNetworkServiceType.name]. + /// Returns the first value with the given name, otherwise `null`. + static URLRequestNetworkServiceType? byName(String? name) { + if (name != null) { + try { + return URLRequestNetworkServiceType.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [URLRequestNetworkServiceType] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in URLRequestNetworkServiceType.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 8: return 'AV_STREAMING'; @@ -119,6 +144,22 @@ class URLRequestNetworkServiceType { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } ///An iOS-specific Class that represents the constants that specify how a request uses network resources. @@ -205,20 +246,45 @@ class IOSURLRequestNetworkServiceType { return null; } + /// Gets a possible [IOSURLRequestNetworkServiceType] instance value with name [name]. + /// + /// Goes through [IOSURLRequestNetworkServiceType.values] looking for a value with + /// name [name], as reported by [IOSURLRequestNetworkServiceType.name]. + /// Returns the first value with the given name, otherwise `null`. + static IOSURLRequestNetworkServiceType? byName(String? name) { + if (name != null) { + try { + return IOSURLRequestNetworkServiceType.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [IOSURLRequestNetworkServiceType] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in IOSURLRequestNetworkServiceType.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 8: return 'AV_STREAMING'; @@ -239,4 +305,20 @@ class IOSURLRequestNetworkServiceType { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/url_response.dart b/flutter_inappwebview_platform_interface/lib/src/types/url_response.dart index 5896d0e93..72316d7bb 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/url_response.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/url_response.dart @@ -1,6 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import '../web_uri.dart'; +import 'enum_method.dart'; part 'url_response.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/url_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/url_response.g.dart index afce902ab..5a59dba61 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/url_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/url_response.g.dart @@ -38,7 +38,8 @@ class URLResponse { this.url}); ///Gets a possible [URLResponse] instance from a [Map] value. - static URLResponse? fromMap(Map? map) { + static URLResponse? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -55,7 +56,7 @@ class URLResponse { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "expectedContentLength": expectedContentLength, "headers": headers, @@ -111,7 +112,8 @@ class IOSURLResponse { this.url}); ///Gets a possible [IOSURLResponse] instance from a [Map] value. - static IOSURLResponse? fromMap(Map? map) { + static IOSURLResponse? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -128,7 +130,7 @@ class IOSURLResponse { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "expectedContentLength": expectedContentLength, "headers": headers, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/user_preferred_content_mode.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/user_preferred_content_mode.g.dart index 38f1ec5ba..941ae6876 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/user_preferred_content_mode.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/user_preferred_content_mode.g.dart @@ -58,20 +58,44 @@ class UserPreferredContentMode { return null; } + /// Gets a possible [UserPreferredContentMode] instance value with name [name]. + /// + /// Goes through [UserPreferredContentMode.values] looking for a value with + /// name [name], as reported by [UserPreferredContentMode.name]. + /// Returns the first value with the given name, otherwise `null`. + static UserPreferredContentMode? byName(String? name) { + if (name != null) { + try { + return UserPreferredContentMode.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [UserPreferredContentMode] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in UserPreferredContentMode.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 2: return 'DESKTOP'; @@ -82,4 +106,20 @@ class UserPreferredContentMode { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/user_script.dart b/flutter_inappwebview_platform_interface/lib/src/types/user_script.dart index cae6b382e..7320e6a15 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/user_script.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/user_script.dart @@ -1,8 +1,9 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; +import 'enum_method.dart'; import 'user_script_injection_time.dart'; import 'content_world.dart'; -import '../platform_webview_feature.dart'; +import '../in_app_webview/platform_inappwebview_controller.dart'; part 'user_script.g.dart'; @@ -23,19 +24,38 @@ class UserScript_ { bool? iosForMainFrameOnly; ///A Boolean value that indicates whether to inject the script into the main frame. - ///Specify true to inject the script only into the main frame, or false to inject it into all frames. + ///Specify `true` to inject the script only into the main frame, or false to inject it into all frames. ///The default value is `true`. - /// - ///**NOTE**: available only on iOS and MacOS. + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WindowsPlatform(), + ]) bool forMainFrameOnly; ///A set of matching rules for the allowed origins. + ///Adding `'*'` as an allowed origin or setting this to `null`, it means it will allow every origin. + ///Instead, an empty [Set] will block every origin. + /// + ///**NOTE for Android**: each origin pattern MUST follow the table rule of [PlatformInAppWebViewController.addWebMessageListener]. /// - ///**NOTE**: available only on Android and only if [WebViewFeature.DOCUMENT_START_SCRIPT] feature is supported. + ///**NOTE for iOS, macOS, Windows**: each origin pattern will be used as a + ///Regular Expression Pattern that will be used on JavaScript side using [RegExp](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp). + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WindowsPlatform(), + ]) late Set allowedOriginRules; ///A scope of execution in which to evaluate the script to prevent conflicts between different scripts. ///For more information about content worlds, see [ContentWorld]. + /// + ///**NOTE for Android**: because of how a Content World is implemented on Android, if [forMainFrameOnly] is `true`, + ///the [source] inside a specific Content World that is not [ContentWorld.PAGE] will not be executed. + ///See [ContentWorld] for more details. late ContentWorld contentWorld; @ExchangeableObjectConstructor() diff --git a/flutter_inappwebview_platform_interface/lib/src/types/user_script.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/user_script.g.dart index 99f114be0..099370534 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/user_script.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/user_script.g.dart @@ -9,19 +9,38 @@ part of 'user_script.dart'; ///Class that represents a script that the `WebView` injects into the web page. class UserScript { ///A set of matching rules for the allowed origins. + ///Adding `'*'` as an allowed origin or setting this to `null`, it means it will allow every origin. + ///Instead, an empty [Set] will block every origin. /// - ///**NOTE**: available only on Android and only if [WebViewFeature.DOCUMENT_START_SCRIPT] feature is supported. + ///**NOTE for Android**: each origin pattern MUST follow the table rule of [PlatformInAppWebViewController.addWebMessageListener]. + /// + ///**NOTE for iOS, macOS, Windows**: each origin pattern will be used as a + ///Regular Expression Pattern that will be used on JavaScript side using [RegExp](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp). + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Windows WebView2 late Set allowedOriginRules; ///A scope of execution in which to evaluate the script to prevent conflicts between different scripts. ///For more information about content worlds, see [ContentWorld]. + /// + ///**NOTE for Android**: because of how a Content World is implemented on Android, if [forMainFrameOnly] is `true`, + ///the [source] inside a specific Content World that is not [ContentWorld.PAGE] will not be executed. + ///See [ContentWorld] for more details. late ContentWorld contentWorld; ///A Boolean value that indicates whether to inject the script into the main frame. - ///Specify true to inject the script only into the main frame, or false to inject it into all frames. + ///Specify `true` to inject the script only into the main frame, or false to inject it into all frames. ///The default value is `true`. /// - ///**NOTE**: available only on iOS and MacOS. + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Windows WebView2 bool forMainFrameOnly; ///The script’s group name. @@ -53,32 +72,50 @@ class UserScript { } ///Gets a possible [UserScript] instance from a [Map] value. - static UserScript? fromMap(Map? map) { + static UserScript? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = UserScript( groupName: map['groupName'], - injectionTime: - UserScriptInjectionTime.fromNativeValue(map['injectionTime'])!, + injectionTime: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + UserScriptInjectionTime.fromNativeValue(map['injectionTime']), + EnumMethod.value => + UserScriptInjectionTime.fromValue(map['injectionTime']), + EnumMethod.name => UserScriptInjectionTime.byName(map['injectionTime']) + }!, iosForMainFrameOnly: map['forMainFrameOnly'], source: map['source'], ); - instance.allowedOriginRules = - Set.from(map['allowedOriginRules']!.cast()); - instance.contentWorld = map['contentWorld']; - instance.forMainFrameOnly = map['forMainFrameOnly']; + if (map['allowedOriginRules'] != null) { + instance.allowedOriginRules = + Set.from(map['allowedOriginRules']!.cast()); + } + if (map['contentWorld'] != null) { + instance.contentWorld = ContentWorld.fromMap( + map['contentWorld']?.cast(), + enumMethod: enumMethod)!; + } + if (map['forMainFrameOnly'] != null) { + instance.forMainFrameOnly = map['forMainFrameOnly']; + } return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "allowedOriginRules": allowedOriginRules.toList(), - "contentWorld": contentWorld.toMap(), + "contentWorld": contentWorld.toMap(enumMethod: enumMethod), "forMainFrameOnly": forMainFrameOnly, "groupName": groupName, - "injectionTime": injectionTime.toNativeValue(), + "injectionTime": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => injectionTime.toNativeValue(), + EnumMethod.value => injectionTime.toValue(), + EnumMethod.name => injectionTime.name() + }, "source": source, }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/user_script_injection_time.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/user_script_injection_time.g.dart index 1dd328d73..26c717bc6 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/user_script_injection_time.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/user_script_injection_time.g.dart @@ -58,26 +58,66 @@ class UserScriptInjectionTime { return null; } + /// Gets a possible [UserScriptInjectionTime] instance value with name [name]. + /// + /// Goes through [UserScriptInjectionTime.values] looking for a value with + /// name [name], as reported by [UserScriptInjectionTime.name]. + /// Returns the first value with the given name, otherwise `null`. + static UserScriptInjectionTime? byName(String? name) { + if (name != null) { + try { + return UserScriptInjectionTime.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [UserScriptInjectionTime] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in UserScriptInjectionTime.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 1: + return 'AT_DOCUMENT_END'; + case 0: + return 'AT_DOCUMENT_START'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { - switch (_value) { - case 1: - return 'AT_DOCUMENT_END'; - case 0: - return 'AT_DOCUMENT_START'; - } - return _value.toString(); + return name(); } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/vertical_scrollbar_position.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/vertical_scrollbar_position.g.dart index c0c9ff89f..e54226fc3 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/vertical_scrollbar_position.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/vertical_scrollbar_position.g.dart @@ -61,20 +61,45 @@ class VerticalScrollbarPosition { return null; } + /// Gets a possible [VerticalScrollbarPosition] instance value with name [name]. + /// + /// Goes through [VerticalScrollbarPosition.values] looking for a value with + /// name [name], as reported by [VerticalScrollbarPosition.name]. + /// Returns the first value with the given name, otherwise `null`. + static VerticalScrollbarPosition? byName(String? name) { + if (name != null) { + try { + return VerticalScrollbarPosition.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [VerticalScrollbarPosition] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in VerticalScrollbarPosition.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 0: return 'SCROLLBAR_POSITION_DEFAULT'; @@ -85,6 +110,22 @@ class VerticalScrollbarPosition { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } ///An Android-specific class used to configure the position of the vertical scroll bar. @@ -145,20 +186,45 @@ class AndroidVerticalScrollbarPosition { return null; } + /// Gets a possible [AndroidVerticalScrollbarPosition] instance value with name [name]. + /// + /// Goes through [AndroidVerticalScrollbarPosition.values] looking for a value with + /// name [name], as reported by [AndroidVerticalScrollbarPosition.name]. + /// Returns the first value with the given name, otherwise `null`. + static AndroidVerticalScrollbarPosition? byName(String? name) { + if (name != null) { + try { + return AndroidVerticalScrollbarPosition.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [AndroidVerticalScrollbarPosition] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in AndroidVerticalScrollbarPosition.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 0: return 'SCROLLBAR_POSITION_DEFAULT'; @@ -169,4 +235,20 @@ class AndroidVerticalScrollbarPosition { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/web_archive_format.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/web_archive_format.g.dart index 661b12ecb..9c4adbc74 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/web_archive_format.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/web_archive_format.g.dart @@ -55,18 +55,64 @@ class WebArchiveFormat { return null; } + /// Gets a possible [WebArchiveFormat] instance value with name [name]. + /// + /// Goes through [WebArchiveFormat.values] looking for a value with + /// name [name], as reported by [WebArchiveFormat.name]. + /// Returns the first value with the given name, otherwise `null`. + static WebArchiveFormat? byName(String? name) { + if (name != null) { + try { + return WebArchiveFormat.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [WebArchiveFormat] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in WebArchiveFormat.values) value.name(): value + }; + ///Gets [String] value. String toValue() => _value; ///Gets [String] native value. String toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'mht': + return 'MHT'; + case 'webarchive': + return 'WEBARCHIVE'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { return _value; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/web_authentication_session_error.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/web_authentication_session_error.g.dart index a26174420..410b9c7f6 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/web_authentication_session_error.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/web_authentication_session_error.g.dart @@ -60,20 +60,45 @@ class WebAuthenticationSessionError { return null; } + /// Gets a possible [WebAuthenticationSessionError] instance value with name [name]. + /// + /// Goes through [WebAuthenticationSessionError.values] looking for a value with + /// name [name], as reported by [WebAuthenticationSessionError.name]. + /// Returns the first value with the given name, otherwise `null`. + static WebAuthenticationSessionError? byName(String? name) { + if (name != null) { + try { + return WebAuthenticationSessionError.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [WebAuthenticationSessionError] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in WebAuthenticationSessionError.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 1: return 'CANCELED_LOGIN'; @@ -84,4 +109,20 @@ class WebAuthenticationSessionError { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/web_history.dart b/flutter_inappwebview_platform_interface/lib/src/types/web_history.dart index 437ab0205..aefe74dc9 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/web_history.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/web_history.dart @@ -1,6 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import 'web_history_item.dart'; +import 'enum_method.dart'; part 'web_history.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/web_history.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/web_history.g.dart index 8fc9c5f28..3feae8759 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/web_history.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/web_history.g.dart @@ -16,25 +16,27 @@ class WebHistory { WebHistory({this.currentIndex, this.list}); ///Gets a possible [WebHistory] instance from a [Map] value. - static WebHistory? fromMap(Map? map) { + static WebHistory? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = WebHistory( currentIndex: map['currentIndex'], list: map['list'] != null - ? List.from(map['list'] - .map((e) => WebHistoryItem.fromMap(e?.cast())!)) + ? List.from(map['list'].map((e) => + WebHistoryItem.fromMap(e?.cast(), + enumMethod: enumMethod)!)) : null, ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "currentIndex": currentIndex, - "list": list?.map((e) => e.toMap()).toList(), + "list": list?.map((e) => e.toMap(enumMethod: enumMethod)).toList(), }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/web_history_item.dart b/flutter_inappwebview_platform_interface/lib/src/types/web_history_item.dart index 657b8837e..c09e9cb48 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/web_history_item.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/web_history_item.dart @@ -2,6 +2,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_i import '../web_uri.dart'; import 'web_history.dart'; +import 'enum_method.dart'; part 'web_history_item.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/web_history_item.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/web_history_item.g.dart index bcffea28a..c52f90d56 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/web_history_item.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/web_history_item.g.dart @@ -12,7 +12,7 @@ class WebHistoryItem { ///Unique id of the navigation history entry. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows + ///- Windows WebView2 int? entryId; ///0-based position index in the back-forward [WebHistory.list]. @@ -38,7 +38,8 @@ class WebHistoryItem { this.url}); ///Gets a possible [WebHistoryItem] instance from a [Map] value. - static WebHistoryItem? fromMap(Map? map) { + static WebHistoryItem? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -55,7 +56,7 @@ class WebHistoryItem { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "entryId": entryId, "index": index, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/web_resource_error.dart b/flutter_inappwebview_platform_interface/lib/src/types/web_resource_error.dart index de20e8c11..a10b0e1eb 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/web_resource_error.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/web_resource_error.dart @@ -1,6 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import 'web_resource_error_type.dart'; +import 'enum_method.dart'; part 'web_resource_error.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/web_resource_error.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/web_resource_error.g.dart index 9638cf607..184c1327e 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/web_resource_error.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/web_resource_error.g.dart @@ -16,22 +16,32 @@ class WebResourceError { WebResourceError({required this.description, required this.type}); ///Gets a possible [WebResourceError] instance from a [Map] value. - static WebResourceError? fromMap(Map? map) { + static WebResourceError? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = WebResourceError( description: map['description'], - type: WebResourceErrorType.fromNativeValue(map['type'])!, + type: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + WebResourceErrorType.fromNativeValue(map['type']), + EnumMethod.value => WebResourceErrorType.fromValue(map['type']), + EnumMethod.name => WebResourceErrorType.byName(map['type']) + }!, ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "description": description, - "type": type.toNativeValue(), + "type": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => type.toNativeValue(), + EnumMethod.value => type.toValue(), + EnumMethod.name => type.name() + }, }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/web_resource_error_type.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/web_resource_error_type.g.dart index bbf3f6d86..1932ca64a 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/web_resource_error_type.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/web_resource_error_type.g.dart @@ -19,8 +19,8 @@ class WebResourceErrorType { ///App Transport Security disallowed a connection because there is no secure network connection. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.appTransportSecurityRequiresSecureConnection](https://developer.apple.com/documentation/foundation/urlerror/code/2882980-apptransportsecurityrequiressecu)) - ///- MacOS ([Official API - URLError.appTransportSecurityRequiresSecureConnection](https://developer.apple.com/documentation/foundation/urlerror/code/2882980-apptransportsecurityrequiressecu)) + ///- iOS WKWebView ([Official API - URLError.appTransportSecurityRequiresSecureConnection](https://developer.apple.com/documentation/foundation/urlerror/code/2882980-apptransportsecurityrequiressecu)) + ///- macOS WKWebView ([Official API - URLError.appTransportSecurityRequiresSecureConnection](https://developer.apple.com/documentation/foundation/urlerror/code/2882980-apptransportsecurityrequiressecu)) static final APP_TRANSPORT_SECURITY_REQUIRES_SECURE_CONNECTION = WebResourceErrorType._internalMultiPlatform( 'APP_TRANSPORT_SECURITY_REQUIRES_SECURE_CONNECTION', () { @@ -38,8 +38,8 @@ class WebResourceErrorType { ///An app or app extension attempted to connect to a background session that is already connected to a process. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.backgroundSessionInUseByAnotherProcess](https://developer.apple.com/documentation/foundation/urlerror/code/2882923-backgroundsessioninusebyanotherp)) - ///- MacOS ([Official API - URLError.backgroundSessionInUseByAnotherProcess](https://developer.apple.com/documentation/foundation/urlerror/code/2882923-backgroundsessioninusebyanotherp)) + ///- iOS WKWebView ([Official API - URLError.backgroundSessionInUseByAnotherProcess](https://developer.apple.com/documentation/foundation/urlerror/code/2882923-backgroundsessioninusebyanotherp)) + ///- macOS WKWebView ([Official API - URLError.backgroundSessionInUseByAnotherProcess](https://developer.apple.com/documentation/foundation/urlerror/code/2882923-backgroundsessioninusebyanotherp)) static final BACKGROUND_SESSION_IN_USE_BY_ANOTHER_PROCESS = WebResourceErrorType._internalMultiPlatform( 'BACKGROUND_SESSION_IN_USE_BY_ANOTHER_PROCESS', () { @@ -57,8 +57,8 @@ class WebResourceErrorType { ///The shared container identifier of the URL session configuration is needed but has not been set. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.backgroundSessionRequiresSharedContainer](https://developer.apple.com/documentation/foundation/urlerror/code/2883169-backgroundsessionrequiressharedc)) - ///- MacOS ([Official API - URLError.backgroundSessionRequiresSharedContainer](https://developer.apple.com/documentation/foundation/urlerror/code/2883169-backgroundsessionrequiressharedc)) + ///- iOS WKWebView ([Official API - URLError.backgroundSessionRequiresSharedContainer](https://developer.apple.com/documentation/foundation/urlerror/code/2883169-backgroundsessionrequiressharedc)) + ///- macOS WKWebView ([Official API - URLError.backgroundSessionRequiresSharedContainer](https://developer.apple.com/documentation/foundation/urlerror/code/2883169-backgroundsessionrequiressharedc)) static final BACKGROUND_SESSION_REQUIRES_SHARED_CONTAINER = WebResourceErrorType._internalMultiPlatform( 'BACKGROUND_SESSION_REQUIRES_SHARED_CONTAINER', () { @@ -76,8 +76,8 @@ class WebResourceErrorType { ///The app is suspended or exits while a background data task is processing. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.backgroundSessionWasDisconnected](https://developer.apple.com/documentation/foundation/urlerror/code/2883075-backgroundsessionwasdisconnected)) - ///- MacOS ([Official API - URLError.backgroundSessionWasDisconnected](https://developer.apple.com/documentation/foundation/urlerror/code/2883075-backgroundsessionwasdisconnected)) + ///- iOS WKWebView ([Official API - URLError.backgroundSessionWasDisconnected](https://developer.apple.com/documentation/foundation/urlerror/code/2883075-backgroundsessionwasdisconnected)) + ///- macOS WKWebView ([Official API - URLError.backgroundSessionWasDisconnected](https://developer.apple.com/documentation/foundation/urlerror/code/2883075-backgroundsessionwasdisconnected)) static final BACKGROUND_SESSION_WAS_DISCONNECTED = WebResourceErrorType._internalMultiPlatform( 'BACKGROUND_SESSION_WAS_DISCONNECTED', () { @@ -95,9 +95,9 @@ class WebResourceErrorType { ///The URL Loading System received bad data from the server. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.badServerResponse](https://developer.apple.com/documentation/foundation/urlerror/2293606-badserverresponse)) - ///- MacOS ([Official API - URLError.badServerResponse](https://developer.apple.com/documentation/foundation/urlerror/2293606-badserverresponse)) - ///- Windows ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_ERROR_HTTP_INVALID_SERVER_RESPONSE](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) + ///- iOS WKWebView ([Official API - URLError.badServerResponse](https://developer.apple.com/documentation/foundation/urlerror/2293606-badserverresponse)) + ///- macOS WKWebView ([Official API - URLError.badServerResponse](https://developer.apple.com/documentation/foundation/urlerror/2293606-badserverresponse)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_ERROR_HTTP_INVALID_SERVER_RESPONSE](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) static final BAD_SERVER_RESPONSE = WebResourceErrorType._internalMultiPlatform('BAD_SERVER_RESPONSE', () { switch (defaultTargetPlatform) { @@ -116,9 +116,9 @@ class WebResourceErrorType { ///A malformed URL prevented a URL request from being initiated. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebViewClient.ERROR_BAD_URL](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_BAD_URL)) - ///- iOS ([Official API - URLError.badURL](https://developer.apple.com/documentation/foundation/urlerror/2293516-badurl)) - ///- MacOS ([Official API - URLError.badURL](https://developer.apple.com/documentation/foundation/urlerror/2293516-badurl)) + ///- Android WebView ([Official API - WebViewClient.ERROR_BAD_URL](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_BAD_URL)) + ///- iOS WKWebView ([Official API - URLError.badURL](https://developer.apple.com/documentation/foundation/urlerror/2293516-badurl)) + ///- macOS WKWebView ([Official API - URLError.badURL](https://developer.apple.com/documentation/foundation/urlerror/2293516-badurl)) static final BAD_URL = WebResourceErrorType._internalMultiPlatform('BAD_URL', () { switch (defaultTargetPlatform) { @@ -137,8 +137,8 @@ class WebResourceErrorType { ///A connection was attempted while a phone call is active on a network that does not support simultaneous phone and data communication (EDGE or GPRS). /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.callIsActive](https://developer.apple.com/documentation/foundation/urlerror/code/2883170-callisactive)) - ///- MacOS ([Official API - URLError.callIsActive](https://developer.apple.com/documentation/foundation/urlerror/code/2883170-callisactive)) + ///- iOS WKWebView ([Official API - URLError.callIsActive](https://developer.apple.com/documentation/foundation/urlerror/code/2883170-callisactive)) + ///- macOS WKWebView ([Official API - URLError.callIsActive](https://developer.apple.com/documentation/foundation/urlerror/code/2883170-callisactive)) static final CALL_IS_ACTIVE = WebResourceErrorType._internalMultiPlatform('CALL_IS_ACTIVE', () { switch (defaultTargetPlatform) { @@ -155,9 +155,9 @@ class WebResourceErrorType { ///An asynchronous load has been canceled. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.cancelled](https://developer.apple.com/documentation/foundation/urlerror/code/2883178-cancelled)) - ///- MacOS ([Official API - URLError.cancelled](https://developer.apple.com/documentation/foundation/urlerror/code/2883178-cancelled)) - ///- Windows ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_OPERATION_CANCELED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) + ///- iOS WKWebView ([Official API - URLError.cancelled](https://developer.apple.com/documentation/foundation/urlerror/code/2883178-cancelled)) + ///- macOS WKWebView ([Official API - URLError.cancelled](https://developer.apple.com/documentation/foundation/urlerror/code/2883178-cancelled)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_OPERATION_CANCELED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) static final CANCELLED = WebResourceErrorType._internalMultiPlatform('CANCELLED', () { switch (defaultTargetPlatform) { @@ -176,8 +176,8 @@ class WebResourceErrorType { ///A download task couldn’t close the downloaded file on disk. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.cannotCloseFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883215-cannotclosefile)) - ///- MacOS ([Official API - URLError.cannotCloseFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883215-cannotclosefile)) + ///- iOS WKWebView ([Official API - URLError.cannotCloseFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883215-cannotclosefile)) + ///- macOS WKWebView ([Official API - URLError.cannotCloseFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883215-cannotclosefile)) static final CANNOT_CLOSE_FILE = WebResourceErrorType._internalMultiPlatform('CANNOT_CLOSE_FILE', () { switch (defaultTargetPlatform) { @@ -194,10 +194,10 @@ class WebResourceErrorType { ///Failed to connect to the server. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebViewClient.ERROR_CONNECT](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_CONNECT)) - ///- iOS ([Official API - URLError.cannotConnectToHost](https://developer.apple.com/documentation/foundation/urlerror/code/2883001-cannotconnecttohost)) - ///- MacOS ([Official API - URLError.cannotConnectToHost](https://developer.apple.com/documentation/foundation/urlerror/code/2883001-cannotconnecttohost)) - ///- Windows ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_CANNOT_CONNECT](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) + ///- Android WebView ([Official API - WebViewClient.ERROR_CONNECT](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_CONNECT)) + ///- iOS WKWebView ([Official API - URLError.cannotConnectToHost](https://developer.apple.com/documentation/foundation/urlerror/code/2883001-cannotconnecttohost)) + ///- macOS WKWebView ([Official API - URLError.cannotConnectToHost](https://developer.apple.com/documentation/foundation/urlerror/code/2883001-cannotconnecttohost)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_CANNOT_CONNECT](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) static final CANNOT_CONNECT_TO_HOST = WebResourceErrorType._internalMultiPlatform('CANNOT_CONNECT_TO_HOST', () { switch (defaultTargetPlatform) { @@ -218,8 +218,8 @@ class WebResourceErrorType { ///A download task couldn’t create the downloaded file on disk because of an I/O failure. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.cannotCreateFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883204-cannotcreatefile)) - ///- MacOS ([Official API - URLError.cannotCreateFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883204-cannotcreatefile)) + ///- iOS WKWebView ([Official API - URLError.cannotCreateFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883204-cannotcreatefile)) + ///- macOS WKWebView ([Official API - URLError.cannotCreateFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883204-cannotcreatefile)) static final CANNOT_CREATE_FILE = WebResourceErrorType._internalMultiPlatform('CANNOT_CREATE_FILE', () { switch (defaultTargetPlatform) { @@ -236,8 +236,8 @@ class WebResourceErrorType { ///Content data received during a connection request couldn’t be decoded for a known content encoding. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.cannotDecodeContentData](https://developer.apple.com/documentation/foundation/urlerror/2292983-cannotdecodecontentdata)) - ///- MacOS ([Official API - URLError.cannotDecodeContentData](https://developer.apple.com/documentation/foundation/urlerror/2292983-cannotdecodecontentdata)) + ///- iOS WKWebView ([Official API - URLError.cannotDecodeContentData](https://developer.apple.com/documentation/foundation/urlerror/2292983-cannotdecodecontentdata)) + ///- macOS WKWebView ([Official API - URLError.cannotDecodeContentData](https://developer.apple.com/documentation/foundation/urlerror/2292983-cannotdecodecontentdata)) static final CANNOT_DECODE_CONTENT_DATA = WebResourceErrorType._internalMultiPlatform('CANNOT_DECODE_CONTENT_DATA', () { @@ -255,8 +255,8 @@ class WebResourceErrorType { ///Content data received during a connection request couldn’t be decoded for a known content encoding. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.cannotDecodeRawData](https://developer.apple.com/documentation/foundation/urlerror/2293573-cannotdecoderawdata)) - ///- MacOS ([Official API - URLError.cannotDecodeRawData](https://developer.apple.com/documentation/foundation/urlerror/2293573-cannotdecoderawdata)) + ///- iOS WKWebView ([Official API - URLError.cannotDecodeRawData](https://developer.apple.com/documentation/foundation/urlerror/2293573-cannotdecoderawdata)) + ///- macOS WKWebView ([Official API - URLError.cannotDecodeRawData](https://developer.apple.com/documentation/foundation/urlerror/2293573-cannotdecoderawdata)) static final CANNOT_DECODE_RAW_DATA = WebResourceErrorType._internalMultiPlatform('CANNOT_DECODE_RAW_DATA', () { switch (defaultTargetPlatform) { @@ -273,8 +273,8 @@ class WebResourceErrorType { ///A request to load an item only from the cache could not be satisfied. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.cannotLoadFromNetwork](https://developer.apple.com/documentation/foundation/urlerror/code/2882968-cannotloadfromnetwork)) - ///- MacOS ([Official API - URLError.cannotLoadFromNetwork](https://developer.apple.com/documentation/foundation/urlerror/code/2882968-cannotloadfromnetwork)) + ///- iOS WKWebView ([Official API - URLError.cannotLoadFromNetwork](https://developer.apple.com/documentation/foundation/urlerror/code/2882968-cannotloadfromnetwork)) + ///- macOS WKWebView ([Official API - URLError.cannotLoadFromNetwork](https://developer.apple.com/documentation/foundation/urlerror/code/2882968-cannotloadfromnetwork)) static final CANNOT_LOAD_FROM_NETWORK = WebResourceErrorType._internalMultiPlatform('CANNOT_LOAD_FROM_NETWORK', () { @@ -292,8 +292,8 @@ class WebResourceErrorType { ///A download task was unable to move a downloaded file on disk. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.cannotMoveFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883180-cannotmovefile)) - ///- MacOS ([Official API - URLError.cannotMoveFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883180-cannotmovefile)) + ///- iOS WKWebView ([Official API - URLError.cannotMoveFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883180-cannotmovefile)) + ///- macOS WKWebView ([Official API - URLError.cannotMoveFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883180-cannotmovefile)) static final CANNOT_MOVE_FILE = WebResourceErrorType._internalMultiPlatform('CANNOT_MOVE_FILE', () { switch (defaultTargetPlatform) { @@ -310,8 +310,8 @@ class WebResourceErrorType { ///A download task was unable to open the downloaded file on disk. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.cannotOpenFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883034-cannotopenfile)) - ///- MacOS ([Official API - URLError.cannotOpenFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883034-cannotopenfile)) + ///- iOS WKWebView ([Official API - URLError.cannotOpenFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883034-cannotopenfile)) + ///- macOS WKWebView ([Official API - URLError.cannotOpenFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883034-cannotopenfile)) static final CANNOT_OPEN_FILE = WebResourceErrorType._internalMultiPlatform('CANNOT_OPEN_FILE', () { switch (defaultTargetPlatform) { @@ -328,8 +328,8 @@ class WebResourceErrorType { ///A task could not parse a response. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.cannotParseResponse](https://developer.apple.com/documentation/foundation/urlerror/code/2882919-cannotparseresponse)) - ///- MacOS ([Official API - URLError.cannotParseResponse](https://developer.apple.com/documentation/foundation/urlerror/code/2882919-cannotparseresponse)) + ///- iOS WKWebView ([Official API - URLError.cannotParseResponse](https://developer.apple.com/documentation/foundation/urlerror/code/2882919-cannotparseresponse)) + ///- macOS WKWebView ([Official API - URLError.cannotParseResponse](https://developer.apple.com/documentation/foundation/urlerror/code/2882919-cannotparseresponse)) static final CANNOT_PARSE_RESPONSE = WebResourceErrorType._internalMultiPlatform('CANNOT_PARSE_RESPONSE', () { switch (defaultTargetPlatform) { @@ -346,8 +346,8 @@ class WebResourceErrorType { ///A download task was unable to remove a downloaded file from disk. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.cannotRemoveFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883202-cannotremovefile)) - ///- MacOS ([Official API - URLError.cannotRemoveFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883202-cannotremovefile)) + ///- iOS WKWebView ([Official API - URLError.cannotRemoveFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883202-cannotremovefile)) + ///- macOS WKWebView ([Official API - URLError.cannotRemoveFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883202-cannotremovefile)) static final CANNOT_REMOVE_FILE = WebResourceErrorType._internalMultiPlatform('CANNOT_REMOVE_FILE', () { switch (defaultTargetPlatform) { @@ -364,8 +364,8 @@ class WebResourceErrorType { ///A download task was unable to write to the downloaded file on disk. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.cannotWriteToFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883098-cannotwritetofile)) - ///- MacOS ([Official API - URLError.cannotWriteToFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883098-cannotwritetofile)) + ///- iOS WKWebView ([Official API - URLError.cannotWriteToFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883098-cannotwritetofile)) + ///- macOS WKWebView ([Official API - URLError.cannotWriteToFile](https://developer.apple.com/documentation/foundation/urlerror/code/2883098-cannotwritetofile)) static final CANNOT_WRITE_TO_FILE = WebResourceErrorType._internalMultiPlatform('CANNOT_WRITE_TO_FILE', () { switch (defaultTargetPlatform) { @@ -382,8 +382,8 @@ class WebResourceErrorType { ///A server certificate was rejected. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.clientCertificateRejected](https://developer.apple.com/documentation/foundation/urlerror/code/2883091-clientcertificaterejected)) - ///- MacOS ([Official API - URLError.clientCertificateRejected](https://developer.apple.com/documentation/foundation/urlerror/code/2883091-clientcertificaterejected)) + ///- iOS WKWebView ([Official API - URLError.clientCertificateRejected](https://developer.apple.com/documentation/foundation/urlerror/code/2883091-clientcertificaterejected)) + ///- macOS WKWebView ([Official API - URLError.clientCertificateRejected](https://developer.apple.com/documentation/foundation/urlerror/code/2883091-clientcertificaterejected)) static final CLIENT_CERTIFICATE_REJECTED = WebResourceErrorType._internalMultiPlatform('CLIENT_CERTIFICATE_REJECTED', () { @@ -401,8 +401,8 @@ class WebResourceErrorType { ///A client certificate was required to authenticate an SSL connection during a request. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.clientCertificateRequired](https://developer.apple.com/documentation/foundation/urlerror/code/2883199-clientcertificaterequired)) - ///- MacOS ([Official API - URLError.clientCertificateRequired](https://developer.apple.com/documentation/foundation/urlerror/code/2883199-clientcertificaterequired)) + ///- iOS WKWebView ([Official API - URLError.clientCertificateRequired](https://developer.apple.com/documentation/foundation/urlerror/code/2883199-clientcertificaterequired)) + ///- macOS WKWebView ([Official API - URLError.clientCertificateRequired](https://developer.apple.com/documentation/foundation/urlerror/code/2883199-clientcertificaterequired)) static final CLIENT_CERTIFICATE_REQUIRED = WebResourceErrorType._internalMultiPlatform('CLIENT_CERTIFICATE_REQUIRED', () { @@ -420,7 +420,7 @@ class WebResourceErrorType { ///Indicates that the connection was stopped. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_CONNECTION_ABORTED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_CONNECTION_ABORTED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) static final CONNECTION_ABORTED = WebResourceErrorType._internalMultiPlatform('CONNECTION_ABORTED', () { switch (defaultTargetPlatform) { @@ -435,8 +435,8 @@ class WebResourceErrorType { ///The length of the resource data exceeds the maximum allowed. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.dataLengthExceedsMaximum](https://developer.apple.com/documentation/foundation/urlerror/code/2882930-datalengthexceedsmaximum)) - ///- MacOS ([Official API - URLError.dataLengthExceedsMaximum](https://developer.apple.com/documentation/foundation/urlerror/code/2882930-datalengthexceedsmaximum)) + ///- iOS WKWebView ([Official API - URLError.dataLengthExceedsMaximum](https://developer.apple.com/documentation/foundation/urlerror/code/2882930-datalengthexceedsmaximum)) + ///- macOS WKWebView ([Official API - URLError.dataLengthExceedsMaximum](https://developer.apple.com/documentation/foundation/urlerror/code/2882930-datalengthexceedsmaximum)) static final DATA_LENGTH_EXCEEDS_MAXIMUM = WebResourceErrorType._internalMultiPlatform('DATA_LENGTH_EXCEEDS_MAXIMUM', () { @@ -454,8 +454,8 @@ class WebResourceErrorType { ///The cellular network disallowed a connection. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.dataNotAllowed](https://developer.apple.com/documentation/foundation/urlerror/code/2883217-datanotallowed)) - ///- MacOS ([Official API - URLError.dataNotAllowed](https://developer.apple.com/documentation/foundation/urlerror/code/2883217-datanotallowed)) + ///- iOS WKWebView ([Official API - URLError.dataNotAllowed](https://developer.apple.com/documentation/foundation/urlerror/code/2883217-datanotallowed)) + ///- macOS WKWebView ([Official API - URLError.dataNotAllowed](https://developer.apple.com/documentation/foundation/urlerror/code/2883217-datanotallowed)) static final DATA_NOT_ALLOWED = WebResourceErrorType._internalMultiPlatform('DATA_NOT_ALLOWED', () { switch (defaultTargetPlatform) { @@ -472,8 +472,8 @@ class WebResourceErrorType { ///A download task failed to decode an encoded file during the download. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.downloadDecodingFailedMidStream](https://developer.apple.com/documentation/foundation/urlerror/code/2883224-downloaddecodingfailedmidstream)) - ///- MacOS ([Official API - URLError.downloadDecodingFailedMidStream](https://developer.apple.com/documentation/foundation/urlerror/code/2883224-downloaddecodingfailedmidstream)) + ///- iOS WKWebView ([Official API - URLError.downloadDecodingFailedMidStream](https://developer.apple.com/documentation/foundation/urlerror/code/2883224-downloaddecodingfailedmidstream)) + ///- macOS WKWebView ([Official API - URLError.downloadDecodingFailedMidStream](https://developer.apple.com/documentation/foundation/urlerror/code/2883224-downloaddecodingfailedmidstream)) static final DOWNLOAD_DECODING_FAILED_MID_STREAM = WebResourceErrorType._internalMultiPlatform( 'DOWNLOAD_DECODING_FAILED_MID_STREAM', () { @@ -491,8 +491,8 @@ class WebResourceErrorType { ///A download task failed to decode an encoded file after downloading. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.downloadDecodingFailedToComplete](https://developer.apple.com/documentation/foundation/urlerror/code/2882936-downloaddecodingfailedtocomplete)) - ///- MacOS ([Official API - URLError.downloadDecodingFailedToComplete](https://developer.apple.com/documentation/foundation/urlerror/code/2882936-downloaddecodingfailedtocomplete)) + ///- iOS WKWebView ([Official API - URLError.downloadDecodingFailedToComplete](https://developer.apple.com/documentation/foundation/urlerror/code/2882936-downloaddecodingfailedtocomplete)) + ///- macOS WKWebView ([Official API - URLError.downloadDecodingFailedToComplete](https://developer.apple.com/documentation/foundation/urlerror/code/2882936-downloaddecodingfailedtocomplete)) static final DOWNLOAD_DECODING_FAILED_TO_COMPLETE = WebResourceErrorType._internalMultiPlatform( 'DOWNLOAD_DECODING_FAILED_TO_COMPLETE', () { @@ -510,7 +510,7 @@ class WebResourceErrorType { ///Failed to perform SSL handshake. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebViewClient.ERROR_FAILED_SSL_HANDSHAKE](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_FAILED_SSL_HANDSHAKE)) + ///- Android WebView ([Official API - WebViewClient.ERROR_FAILED_SSL_HANDSHAKE](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_FAILED_SSL_HANDSHAKE)) static final FAILED_SSL_HANDSHAKE = WebResourceErrorType._internalMultiPlatform('FAILED_SSL_HANDSHAKE', () { switch (defaultTargetPlatform) { @@ -525,8 +525,8 @@ class WebResourceErrorType { ///A request for an FTP file resulted in the server responding that the file is not a plain file, but a directory. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.fileIsDirectory](https://developer.apple.com/documentation/foundation/urlerror/code/2883220-fileisdirectory)) - ///- MacOS ([Official API - URLError.fileIsDirectory](https://developer.apple.com/documentation/foundation/urlerror/code/2883220-fileisdirectory)) + ///- iOS WKWebView ([Official API - URLError.fileIsDirectory](https://developer.apple.com/documentation/foundation/urlerror/code/2883220-fileisdirectory)) + ///- macOS WKWebView ([Official API - URLError.fileIsDirectory](https://developer.apple.com/documentation/foundation/urlerror/code/2883220-fileisdirectory)) static final FILE_IS_DIRECTORY = WebResourceErrorType._internalMultiPlatform('FILE_IS_DIRECTORY', () { switch (defaultTargetPlatform) { @@ -543,9 +543,9 @@ class WebResourceErrorType { ///File not found. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebViewClient.ERROR_FILE_NOT_FOUND](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_FILE_NOT_FOUND)) - ///- iOS ([Official API - URLError.fileDoesNotExist](https://developer.apple.com/documentation/foundation/urlerror/code/2883074-filedoesnotexist)) - ///- MacOS ([Official API - URLError.fileDoesNotExist](https://developer.apple.com/documentation/foundation/urlerror/code/2883074-filedoesnotexist)) + ///- Android WebView ([Official API - WebViewClient.ERROR_FILE_NOT_FOUND](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_FILE_NOT_FOUND)) + ///- iOS WKWebView ([Official API - URLError.fileDoesNotExist](https://developer.apple.com/documentation/foundation/urlerror/code/2883074-filedoesnotexist)) + ///- macOS WKWebView ([Official API - URLError.fileDoesNotExist](https://developer.apple.com/documentation/foundation/urlerror/code/2883074-filedoesnotexist)) static final FILE_NOT_FOUND = WebResourceErrorType._internalMultiPlatform('FILE_NOT_FOUND', () { switch (defaultTargetPlatform) { @@ -564,7 +564,7 @@ class WebResourceErrorType { ///Generic file error. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebViewClient.ERROR_FILE](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_FILE)) + ///- Android WebView ([Official API - WebViewClient.ERROR_FILE](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_FILE)) static final GENERIC_FILE_ERROR = WebResourceErrorType._internalMultiPlatform('GENERIC_FILE_ERROR', () { switch (defaultTargetPlatform) { @@ -579,10 +579,10 @@ class WebResourceErrorType { ///Server or proxy hostname lookup failed. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebViewClient.ERROR_HOST_LOOKUP](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_HOST_LOOKUP)) - ///- iOS ([Official API - URLError.cannotFindHost](https://developer.apple.com/documentation/foundation/urlerror/code/2883157-cannotfindhost)) - ///- MacOS ([Official API - URLError.cannotFindHost](https://developer.apple.com/documentation/foundation/urlerror/code/2883157-cannotfindhost)) - ///- Windows ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_HOST_NAME_NOT_RESOLVED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) + ///- Android WebView ([Official API - WebViewClient.ERROR_HOST_LOOKUP](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_HOST_LOOKUP)) + ///- iOS WKWebView ([Official API - URLError.cannotFindHost](https://developer.apple.com/documentation/foundation/urlerror/code/2883157-cannotfindhost)) + ///- macOS WKWebView ([Official API - URLError.cannotFindHost](https://developer.apple.com/documentation/foundation/urlerror/code/2883157-cannotfindhost)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_HOST_NAME_NOT_RESOLVED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) static final HOST_LOOKUP = WebResourceErrorType._internalMultiPlatform('HOST_LOOKUP', () { switch (defaultTargetPlatform) { @@ -603,8 +603,8 @@ class WebResourceErrorType { ///The attempted connection required activating a data context while roaming, but international roaming is disabled. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.internationalRoamingOff](https://developer.apple.com/documentation/foundation/urlerror/code/2883134-internationalroamingoff)) - ///- MacOS ([Official API - URLError.internationalRoamingOff](https://developer.apple.com/documentation/foundation/urlerror/code/2883134-internationalroamingoff)) + ///- iOS WKWebView ([Official API - URLError.internationalRoamingOff](https://developer.apple.com/documentation/foundation/urlerror/code/2883134-internationalroamingoff)) + ///- macOS WKWebView ([Official API - URLError.internationalRoamingOff](https://developer.apple.com/documentation/foundation/urlerror/code/2883134-internationalroamingoff)) static final INTERNATIONAL_ROAMING_OFF = WebResourceErrorType._internalMultiPlatform('INTERNATIONAL_ROAMING_OFF', () { @@ -622,7 +622,7 @@ class WebResourceErrorType { ///Failed to read or write to the server. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebViewClient.ERROR_IO](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_IO)) + ///- Android WebView ([Official API - WebViewClient.ERROR_IO](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_IO)) static final IO = WebResourceErrorType._internalMultiPlatform('IO', () { switch (defaultTargetPlatform) { case TargetPlatform.android: @@ -636,9 +636,9 @@ class WebResourceErrorType { ///A client or server connection was severed in the middle of an in-progress load. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.networkConnectionLost](https://developer.apple.com/documentation/foundation/urlerror/2293759-networkconnectionlost)) - ///- MacOS ([Official API - URLError.networkConnectionLost](https://developer.apple.com/documentation/foundation/urlerror/2293759-networkconnectionlost)) - ///- Windows ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_DISCONNECTED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) + ///- iOS WKWebView ([Official API - URLError.networkConnectionLost](https://developer.apple.com/documentation/foundation/urlerror/2293759-networkconnectionlost)) + ///- macOS WKWebView ([Official API - URLError.networkConnectionLost](https://developer.apple.com/documentation/foundation/urlerror/2293759-networkconnectionlost)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_DISCONNECTED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) static final NETWORK_CONNECTION_LOST = WebResourceErrorType._internalMultiPlatform('NETWORK_CONNECTION_LOST', () { @@ -658,8 +658,8 @@ class WebResourceErrorType { ///A network resource was requested, but an internet connection hasn’t been established and can’t be established automatically. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.notConnectedToInternet](https://developer.apple.com/documentation/foundation/urlerror/2293104-notconnectedtointernet)) - ///- MacOS ([Official API - URLError.notConnectedToInternet](https://developer.apple.com/documentation/foundation/urlerror/2293104-notconnectedtointernet)) + ///- iOS WKWebView ([Official API - URLError.notConnectedToInternet](https://developer.apple.com/documentation/foundation/urlerror/2293104-notconnectedtointernet)) + ///- macOS WKWebView ([Official API - URLError.notConnectedToInternet](https://developer.apple.com/documentation/foundation/urlerror/2293104-notconnectedtointernet)) static final NOT_CONNECTED_TO_INTERNET = WebResourceErrorType._internalMultiPlatform('NOT_CONNECTED_TO_INTERNET', () { @@ -677,8 +677,8 @@ class WebResourceErrorType { ///A resource couldn’t be read because of insufficient permissions. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.noPermissionsToReadFile](https://developer.apple.com/documentation/foundation/urlerror/code/2882941-nopermissionstoreadfile)) - ///- MacOS ([Official API - URLError.noPermissionsToReadFile](https://developer.apple.com/documentation/foundation/urlerror/code/2882941-nopermissionstoreadfile)) + ///- iOS WKWebView ([Official API - URLError.noPermissionsToReadFile](https://developer.apple.com/documentation/foundation/urlerror/code/2882941-nopermissionstoreadfile)) + ///- macOS WKWebView ([Official API - URLError.noPermissionsToReadFile](https://developer.apple.com/documentation/foundation/urlerror/code/2882941-nopermissionstoreadfile)) static final NO_PERMISSIONS_TO_READ_FILE = WebResourceErrorType._internalMultiPlatform('NO_PERMISSIONS_TO_READ_FILE', () { @@ -696,7 +696,7 @@ class WebResourceErrorType { ///User authentication failed on proxy. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebViewClient.ERROR_PROXY_AUTHENTICATION](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_PROXY_AUTHENTICATION)) + ///- Android WebView ([Official API - WebViewClient.ERROR_PROXY_AUTHENTICATION](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_PROXY_AUTHENTICATION)) static final PROXY_AUTHENTICATION = WebResourceErrorType._internalMultiPlatform('PROXY_AUTHENTICATION', () { switch (defaultTargetPlatform) { @@ -711,7 +711,7 @@ class WebResourceErrorType { ///Indicates that the request redirect failed. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_REDIRECT_FAILED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_REDIRECT_FAILED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) static final REDIRECT_FAILED = WebResourceErrorType._internalMultiPlatform('REDIRECT_FAILED', () { switch (defaultTargetPlatform) { @@ -726,8 +726,8 @@ class WebResourceErrorType { ///A redirect was specified by way of server response code, but the server didn’t accompany this code with a redirect URL. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.redirectToNonExistentLocation](https://developer.apple.com/documentation/foundation/urlerror/2293066-redirecttononexistentlocation)) - ///- MacOS ([Official API - URLError.redirectToNonExistentLocation](https://developer.apple.com/documentation/foundation/urlerror/2293066-redirecttononexistentlocation)) + ///- iOS WKWebView ([Official API - URLError.redirectToNonExistentLocation](https://developer.apple.com/documentation/foundation/urlerror/2293066-redirecttononexistentlocation)) + ///- macOS WKWebView ([Official API - URLError.redirectToNonExistentLocation](https://developer.apple.com/documentation/foundation/urlerror/2293066-redirecttononexistentlocation)) static final REDIRECT_TO_NON_EXISTENT_LOCATION = WebResourceErrorType._internalMultiPlatform( 'REDIRECT_TO_NON_EXISTENT_LOCATION', () { @@ -745,8 +745,8 @@ class WebResourceErrorType { ///A body stream is needed but the client did not provide one. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.requestBodyStreamExhausted](https://developer.apple.com/documentation/foundation/urlerror/code/2883176-requestbodystreamexhausted)) - ///- MacOS ([Official API - URLError.requestBodyStreamExhausted](https://developer.apple.com/documentation/foundation/urlerror/code/2883176-requestbodystreamexhausted)) + ///- iOS WKWebView ([Official API - URLError.requestBodyStreamExhausted](https://developer.apple.com/documentation/foundation/urlerror/code/2883176-requestbodystreamexhausted)) + ///- macOS WKWebView ([Official API - URLError.requestBodyStreamExhausted](https://developer.apple.com/documentation/foundation/urlerror/code/2883176-requestbodystreamexhausted)) static final REQUEST_BODY_STREAM_EXHAUSTED = WebResourceErrorType._internalMultiPlatform( 'REQUEST_BODY_STREAM_EXHAUSTED', () { @@ -764,7 +764,7 @@ class WebResourceErrorType { ///Indicates that the connection was reset. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_CONNECTION_RESET](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_CONNECTION_RESET](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) static final RESET = WebResourceErrorType._internalMultiPlatform('RESET', () { switch (defaultTargetPlatform) { case TargetPlatform.windows: @@ -779,8 +779,8 @@ class WebResourceErrorType { ///This error can indicate a file-not-found situation, or decoding problems that prevent data from being processed correctly. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.resourceUnavailable](https://developer.apple.com/documentation/foundation/urlerror/2293555-resourceunavailable)) - ///- MacOS ([Official API - URLError.resourceUnavailable](https://developer.apple.com/documentation/foundation/urlerror/2293555-resourceunavailable)) + ///- iOS WKWebView ([Official API - URLError.resourceUnavailable](https://developer.apple.com/documentation/foundation/urlerror/2293555-resourceunavailable)) + ///- macOS WKWebView ([Official API - URLError.resourceUnavailable](https://developer.apple.com/documentation/foundation/urlerror/2293555-resourceunavailable)) static final RESOURCE_UNAVAILABLE = WebResourceErrorType._internalMultiPlatform('RESOURCE_UNAVAILABLE', () { switch (defaultTargetPlatform) { @@ -797,8 +797,8 @@ class WebResourceErrorType { ///An attempt to establish a secure connection failed for reasons that can’t be expressed more specifically. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.secureConnectionFailed](https://developer.apple.com/documentation/foundation/urlerror/code/2883122-secureconnectionfailed)) - ///- MacOS ([Official API - URLError.secureConnectionFailed](https://developer.apple.com/documentation/foundation/urlerror/code/2883122-secureconnectionfailed)) + ///- iOS WKWebView ([Official API - URLError.secureConnectionFailed](https://developer.apple.com/documentation/foundation/urlerror/code/2883122-secureconnectionfailed)) + ///- macOS WKWebView ([Official API - URLError.secureConnectionFailed](https://developer.apple.com/documentation/foundation/urlerror/code/2883122-secureconnectionfailed)) static final SECURE_CONNECTION_FAILED = WebResourceErrorType._internalMultiPlatform('SECURE_CONNECTION_FAILED', () { @@ -816,8 +816,8 @@ class WebResourceErrorType { ///A server certificate had a date which indicates it has expired, or is not yet valid. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.serverCertificateHasBadDate](https://developer.apple.com/documentation/foundation/urlerror/code/2883088-servercertificatehasbaddate)) - ///- MacOS ([Official API - URLError.serverCertificateHasBadDate](https://developer.apple.com/documentation/foundation/urlerror/code/2883088-servercertificatehasbaddate)) + ///- iOS WKWebView ([Official API - URLError.serverCertificateHasBadDate](https://developer.apple.com/documentation/foundation/urlerror/code/2883088-servercertificatehasbaddate)) + ///- macOS WKWebView ([Official API - URLError.serverCertificateHasBadDate](https://developer.apple.com/documentation/foundation/urlerror/code/2883088-servercertificatehasbaddate)) static final SERVER_CERTIFICATE_HAS_BAD_DATE = WebResourceErrorType._internalMultiPlatform( 'SERVER_CERTIFICATE_HAS_BAD_DATE', () { @@ -835,8 +835,8 @@ class WebResourceErrorType { ///A server certificate was not signed by any root server. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.serverCertificateHasUnknownRoot](https://developer.apple.com/documentation/foundation/urlerror/code/2883085-servercertificatehasunknownroot)) - ///- MacOS ([Official API - URLError.serverCertificateHasUnknownRoot](https://developer.apple.com/documentation/foundation/urlerror/code/2883085-servercertificatehasunknownroot)) + ///- iOS WKWebView ([Official API - URLError.serverCertificateHasUnknownRoot](https://developer.apple.com/documentation/foundation/urlerror/code/2883085-servercertificatehasunknownroot)) + ///- macOS WKWebView ([Official API - URLError.serverCertificateHasUnknownRoot](https://developer.apple.com/documentation/foundation/urlerror/code/2883085-servercertificatehasunknownroot)) static final SERVER_CERTIFICATE_HAS_UNKNOWN_ROOT = WebResourceErrorType._internalMultiPlatform( 'SERVER_CERTIFICATE_HAS_UNKNOWN_ROOT', () { @@ -854,8 +854,8 @@ class WebResourceErrorType { ///A server certificate is not yet valid. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.serverCertificateNotYetValid](https://developer.apple.com/documentation/foundation/urlerror/code/2882991-servercertificatenotyetvalid)) - ///- MacOS ([Official API - URLError.serverCertificateNotYetValid](https://developer.apple.com/documentation/foundation/urlerror/code/2882991-servercertificatenotyetvalid)) + ///- iOS WKWebView ([Official API - URLError.serverCertificateNotYetValid](https://developer.apple.com/documentation/foundation/urlerror/code/2882991-servercertificatenotyetvalid)) + ///- macOS WKWebView ([Official API - URLError.serverCertificateNotYetValid](https://developer.apple.com/documentation/foundation/urlerror/code/2882991-servercertificatenotyetvalid)) static final SERVER_CERTIFICATE_NOT_YET_VALID = WebResourceErrorType._internalMultiPlatform( 'SERVER_CERTIFICATE_NOT_YET_VALID', () { @@ -873,8 +873,8 @@ class WebResourceErrorType { ///A server certificate was signed by a root server that isn’t trusted. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.serverCertificateUntrusted](https://developer.apple.com/documentation/foundation/urlerror/code/2882976-servercertificateuntrusted)) - ///- MacOS ([Official API - URLError.serverCertificateUntrusted](https://developer.apple.com/documentation/foundation/urlerror/code/2882976-servercertificateuntrusted)) + ///- iOS WKWebView ([Official API - URLError.serverCertificateUntrusted](https://developer.apple.com/documentation/foundation/urlerror/code/2882976-servercertificateuntrusted)) + ///- macOS WKWebView ([Official API - URLError.serverCertificateUntrusted](https://developer.apple.com/documentation/foundation/urlerror/code/2882976-servercertificateuntrusted)) static final SERVER_CERTIFICATE_UNTRUSTED = WebResourceErrorType._internalMultiPlatform( 'SERVER_CERTIFICATE_UNTRUSTED', () { @@ -892,7 +892,7 @@ class WebResourceErrorType { ///Indicates that the host is unreachable. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_SERVER_UNREACHABLE](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_SERVER_UNREACHABLE](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) static final SERVER_UNREACHABLE = WebResourceErrorType._internalMultiPlatform('SERVER_UNREACHABLE', () { switch (defaultTargetPlatform) { @@ -907,10 +907,10 @@ class WebResourceErrorType { ///Connection timed out. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebViewClient.ERROR_TIMEOUT](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_TIMEOUT)) - ///- iOS ([Official API - URLError.timedOut](https://developer.apple.com/documentation/foundation/urlerror/code/2883027-timedout)) - ///- MacOS ([Official API - URLError.timedOut](https://developer.apple.com/documentation/foundation/urlerror/code/2883027-timedout)) - ///- Windows ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_TIMEOUT](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) + ///- Android WebView ([Official API - WebViewClient.ERROR_TIMEOUT](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_TIMEOUT)) + ///- iOS WKWebView ([Official API - URLError.timedOut](https://developer.apple.com/documentation/foundation/urlerror/code/2883027-timedout)) + ///- macOS WKWebView ([Official API - URLError.timedOut](https://developer.apple.com/documentation/foundation/urlerror/code/2883027-timedout)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_TIMEOUT](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) static final TIMEOUT = WebResourceErrorType._internalMultiPlatform('TIMEOUT', () { switch (defaultTargetPlatform) { @@ -931,9 +931,9 @@ class WebResourceErrorType { ///A redirect loop has been detected or the threshold for number of allowable redirects has been exceeded (currently `16` on iOS). /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebViewClient.ERROR_REDIRECT_LOOP](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_REDIRECT_LOOP)) - ///- iOS ([Official API - URLError.httpTooManyRedirects](https://developer.apple.com/documentation/foundation/urlerror/code/2883099-httptoomanyredirects)) - ///- MacOS ([Official API - URLError.httpTooManyRedirects](https://developer.apple.com/documentation/foundation/urlerror/code/2883099-httptoomanyredirects)) + ///- Android WebView ([Official API - WebViewClient.ERROR_REDIRECT_LOOP](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_REDIRECT_LOOP)) + ///- iOS WKWebView ([Official API - URLError.httpTooManyRedirects](https://developer.apple.com/documentation/foundation/urlerror/code/2883099-httptoomanyredirects)) + ///- macOS WKWebView ([Official API - URLError.httpTooManyRedirects](https://developer.apple.com/documentation/foundation/urlerror/code/2883099-httptoomanyredirects)) static final TOO_MANY_REDIRECTS = WebResourceErrorType._internalMultiPlatform('TOO_MANY_REDIRECTS', () { switch (defaultTargetPlatform) { @@ -952,7 +952,7 @@ class WebResourceErrorType { ///Too many requests during this load. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebViewClient.ERROR_TOO_MANY_REQUESTS](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_TOO_MANY_REQUESTS)) + ///- Android WebView ([Official API - WebViewClient.ERROR_TOO_MANY_REQUESTS](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_TOO_MANY_REQUESTS)) static final TOO_MANY_REQUESTS = WebResourceErrorType._internalMultiPlatform('TOO_MANY_REQUESTS', () { switch (defaultTargetPlatform) { @@ -967,7 +967,7 @@ class WebResourceErrorType { ///Indicates that an unexpected error occurred. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_UNEXPECTED_ERROR](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_UNEXPECTED_ERROR](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) static final UNEXPECTED_ERROR = WebResourceErrorType._internalMultiPlatform('UNEXPECTED_ERROR', () { switch (defaultTargetPlatform) { @@ -982,10 +982,10 @@ class WebResourceErrorType { ///The URL Loading System encountered an error that it can’t interpret. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebViewClient.ERROR_UNKNOWN](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_UNKNOWN)) - ///- iOS ([Official API - URLError.unknown](https://developer.apple.com/documentation/foundation/urlerror/2293357-unknown)) - ///- MacOS ([Official API - URLError.unknown](https://developer.apple.com/documentation/foundation/urlerror/2293357-unknown)) - ///- Windows ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_UNKNOWN](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) + ///- Android WebView ([Official API - WebViewClient.ERROR_UNKNOWN](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_UNKNOWN)) + ///- iOS WKWebView ([Official API - URLError.unknown](https://developer.apple.com/documentation/foundation/urlerror/2293357-unknown)) + ///- macOS WKWebView ([Official API - URLError.unknown](https://developer.apple.com/documentation/foundation/urlerror/2293357-unknown)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_UNKNOWN](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) static final UNKNOWN = WebResourceErrorType._internalMultiPlatform('UNKNOWN', () { switch (defaultTargetPlatform) { @@ -1006,7 +1006,7 @@ class WebResourceErrorType { ///Resource load was canceled by Safe Browsing. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebViewClient.ERROR_UNSAFE_RESOURCE](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_UNSAFE_RESOURCE)) + ///- Android WebView ([Official API - WebViewClient.ERROR_UNSAFE_RESOURCE](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_UNSAFE_RESOURCE)) static final UNSAFE_RESOURCE = WebResourceErrorType._internalMultiPlatform('UNSAFE_RESOURCE', () { switch (defaultTargetPlatform) { @@ -1021,7 +1021,7 @@ class WebResourceErrorType { ///Unsupported authentication scheme (not basic or digest). /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebViewClient.ERROR_UNSUPPORTED_AUTH_SCHEME](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_UNSUPPORTED_AUTH_SCHEME)) + ///- Android WebView ([Official API - WebViewClient.ERROR_UNSUPPORTED_AUTH_SCHEME](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_UNSUPPORTED_AUTH_SCHEME)) static final UNSUPPORTED_AUTH_SCHEME = WebResourceErrorType._internalMultiPlatform('UNSUPPORTED_AUTH_SCHEME', () { @@ -1038,9 +1038,9 @@ class WebResourceErrorType { ///Typically this occurs when there is no available protocol handler for the URL. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebViewClient.ERROR_UNSUPPORTED_SCHEME](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_UNSUPPORTED_SCHEME)) - ///- iOS ([Official API - URLError.unsupportedURL](https://developer.apple.com/documentation/foundation/urlerror/code/2883043-unsupportedurl)) - ///- MacOS ([Official API - URLError.unsupportedURL](https://developer.apple.com/documentation/foundation/urlerror/code/2883043-unsupportedurl)) + ///- Android WebView ([Official API - WebViewClient.ERROR_UNSUPPORTED_SCHEME](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_UNSUPPORTED_SCHEME)) + ///- iOS WKWebView ([Official API - URLError.unsupportedURL](https://developer.apple.com/documentation/foundation/urlerror/code/2883043-unsupportedurl)) + ///- macOS WKWebView ([Official API - URLError.unsupportedURL](https://developer.apple.com/documentation/foundation/urlerror/code/2883043-unsupportedurl)) static final UNSUPPORTED_SCHEME = WebResourceErrorType._internalMultiPlatform('UNSUPPORTED_SCHEME', () { switch (defaultTargetPlatform) { @@ -1059,7 +1059,7 @@ class WebResourceErrorType { ///User authentication failed on server. /// ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebViewClient.ERROR_AUTHENTICATION](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_AUTHENTICATION)) + ///- Android WebView ([Official API - WebViewClient.ERROR_AUTHENTICATION](https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_AUTHENTICATION)) static final USER_AUTHENTICATION_FAILED = WebResourceErrorType._internalMultiPlatform('USER_AUTHENTICATION_FAILED', () { @@ -1075,9 +1075,9 @@ class WebResourceErrorType { ///Authentication is required to access a resource. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.userAuthenticationRequired](https://developer.apple.com/documentation/foundation/urlerror/2293560-userauthenticationrequired)) - ///- MacOS ([Official API - URLError.userAuthenticationRequired](https://developer.apple.com/documentation/foundation/urlerror/2293560-userauthenticationrequired)) - ///- Windows ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_VALID_AUTHENTICATION_CREDENTIALS_REQUIRED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) + ///- iOS WKWebView ([Official API - URLError.userAuthenticationRequired](https://developer.apple.com/documentation/foundation/urlerror/2293560-userauthenticationrequired)) + ///- macOS WKWebView ([Official API - URLError.userAuthenticationRequired](https://developer.apple.com/documentation/foundation/urlerror/2293560-userauthenticationrequired)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_VALID_AUTHENTICATION_CREDENTIALS_REQUIRED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) static final USER_AUTHENTICATION_REQUIRED = WebResourceErrorType._internalMultiPlatform( 'USER_AUTHENTICATION_REQUIRED', () { @@ -1098,8 +1098,8 @@ class WebResourceErrorType { ///This error typically occurs when a user clicks a "Cancel" button in a username/password dialog, rather than attempting to authenticate. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.userCancelledAuthentication](https://developer.apple.com/documentation/foundation/urlerror/2293330-usercancelledauthentication)) - ///- MacOS ([Official API - URLError.userCancelledAuthentication](https://developer.apple.com/documentation/foundation/urlerror/2293330-usercancelledauthentication)) + ///- iOS WKWebView ([Official API - URLError.userCancelledAuthentication](https://developer.apple.com/documentation/foundation/urlerror/2293330-usercancelledauthentication)) + ///- macOS WKWebView ([Official API - URLError.userCancelledAuthentication](https://developer.apple.com/documentation/foundation/urlerror/2293330-usercancelledauthentication)) static final USER_CANCELLED_AUTHENTICATION = WebResourceErrorType._internalMultiPlatform( 'USER_CANCELLED_AUTHENTICATION', () { @@ -1117,7 +1117,7 @@ class WebResourceErrorType { ///Indicates that user lacks proper authentication credentials for a proxy server. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_VALID_PROXY_AUTHENTICATION_REQUIRED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) + ///- Windows WebView2 ([Official API - COREWEBVIEW2_WEB_ERROR_STATUS_VALID_PROXY_AUTHENTICATION_REQUIRED](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#corewebview2_web_error_status)) static final VALID_PROXY_AUTHENTICATION_REQUIRED = WebResourceErrorType._internalMultiPlatform( 'VALID_PROXY_AUTHENTICATION_REQUIRED', () { @@ -1133,8 +1133,8 @@ class WebResourceErrorType { ///A server reported that a URL has a non-zero content length, but terminated the network connection gracefully without sending any data. /// ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - URLError.zeroByteResource](https://developer.apple.com/documentation/foundation/urlerror/2293773-zerobyteresource)) - ///- MacOS ([Official API - URLError.zeroByteResource](https://developer.apple.com/documentation/foundation/urlerror/2293773-zerobyteresource)) + ///- iOS WKWebView ([Official API - URLError.zeroByteResource](https://developer.apple.com/documentation/foundation/urlerror/2293773-zerobyteresource)) + ///- macOS WKWebView ([Official API - URLError.zeroByteResource](https://developer.apple.com/documentation/foundation/urlerror/2293773-zerobyteresource)) static final ZERO_BYTE_RESOURCE = WebResourceErrorType._internalMultiPlatform('ZERO_BYTE_RESOURCE', () { switch (defaultTargetPlatform) { @@ -1239,18 +1239,182 @@ class WebResourceErrorType { return null; } + /// Gets a possible [WebResourceErrorType] instance value with name [name]. + /// + /// Goes through [WebResourceErrorType.values] looking for a value with + /// name [name], as reported by [WebResourceErrorType.name]. + /// Returns the first value with the given name, otherwise `null`. + static WebResourceErrorType? byName(String? name) { + if (name != null) { + try { + return WebResourceErrorType.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [WebResourceErrorType] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in WebResourceErrorType.values) value.name(): value + }; + ///Gets [String] value. String toValue() => _value; - ///Gets [int?] native value. + ///Gets [int] native value if supported by the current platform, otherwise `null`. int? toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'APP_TRANSPORT_SECURITY_REQUIRES_SECURE_CONNECTION': + return 'APP_TRANSPORT_SECURITY_REQUIRES_SECURE_CONNECTION'; + case 'BACKGROUND_SESSION_IN_USE_BY_ANOTHER_PROCESS': + return 'BACKGROUND_SESSION_IN_USE_BY_ANOTHER_PROCESS'; + case 'BACKGROUND_SESSION_REQUIRES_SHARED_CONTAINER': + return 'BACKGROUND_SESSION_REQUIRES_SHARED_CONTAINER'; + case 'BACKGROUND_SESSION_WAS_DISCONNECTED': + return 'BACKGROUND_SESSION_WAS_DISCONNECTED'; + case 'BAD_SERVER_RESPONSE': + return 'BAD_SERVER_RESPONSE'; + case 'BAD_URL': + return 'BAD_URL'; + case 'CALL_IS_ACTIVE': + return 'CALL_IS_ACTIVE'; + case 'CANCELLED': + return 'CANCELLED'; + case 'CANNOT_CLOSE_FILE': + return 'CANNOT_CLOSE_FILE'; + case 'CANNOT_CONNECT_TO_HOST': + return 'CANNOT_CONNECT_TO_HOST'; + case 'CANNOT_CREATE_FILE': + return 'CANNOT_CREATE_FILE'; + case 'CANNOT_DECODE_CONTENT_DATA': + return 'CANNOT_DECODE_CONTENT_DATA'; + case 'CANNOT_DECODE_RAW_DATA': + return 'CANNOT_DECODE_RAW_DATA'; + case 'CANNOT_LOAD_FROM_NETWORK': + return 'CANNOT_LOAD_FROM_NETWORK'; + case 'CANNOT_MOVE_FILE': + return 'CANNOT_MOVE_FILE'; + case 'CANNOT_OPEN_FILE': + return 'CANNOT_OPEN_FILE'; + case 'CANNOT_PARSE_RESPONSE': + return 'CANNOT_PARSE_RESPONSE'; + case 'CANNOT_REMOVE_FILE': + return 'CANNOT_REMOVE_FILE'; + case 'CANNOT_WRITE_TO_FILE': + return 'CANNOT_WRITE_TO_FILE'; + case 'CLIENT_CERTIFICATE_REJECTED': + return 'CLIENT_CERTIFICATE_REJECTED'; + case 'CLIENT_CERTIFICATE_REQUIRED': + return 'CLIENT_CERTIFICATE_REQUIRED'; + case 'CONNECTION_ABORTED': + return 'CONNECTION_ABORTED'; + case 'DATA_LENGTH_EXCEEDS_MAXIMUM': + return 'DATA_LENGTH_EXCEEDS_MAXIMUM'; + case 'DATA_NOT_ALLOWED': + return 'DATA_NOT_ALLOWED'; + case 'DOWNLOAD_DECODING_FAILED_MID_STREAM': + return 'DOWNLOAD_DECODING_FAILED_MID_STREAM'; + case 'DOWNLOAD_DECODING_FAILED_TO_COMPLETE': + return 'DOWNLOAD_DECODING_FAILED_TO_COMPLETE'; + case 'FAILED_SSL_HANDSHAKE': + return 'FAILED_SSL_HANDSHAKE'; + case 'FILE_IS_DIRECTORY': + return 'FILE_IS_DIRECTORY'; + case 'FILE_NOT_FOUND': + return 'FILE_NOT_FOUND'; + case 'GENERIC_FILE_ERROR': + return 'GENERIC_FILE_ERROR'; + case 'HOST_LOOKUP': + return 'HOST_LOOKUP'; + case 'INTERNATIONAL_ROAMING_OFF': + return 'INTERNATIONAL_ROAMING_OFF'; + case 'IO': + return 'IO'; + case 'NETWORK_CONNECTION_LOST': + return 'NETWORK_CONNECTION_LOST'; + case 'NOT_CONNECTED_TO_INTERNET': + return 'NOT_CONNECTED_TO_INTERNET'; + case 'NO_PERMISSIONS_TO_READ_FILE': + return 'NO_PERMISSIONS_TO_READ_FILE'; + case 'PROXY_AUTHENTICATION': + return 'PROXY_AUTHENTICATION'; + case 'REDIRECT_FAILED': + return 'REDIRECT_FAILED'; + case 'REDIRECT_TO_NON_EXISTENT_LOCATION': + return 'REDIRECT_TO_NON_EXISTENT_LOCATION'; + case 'REQUEST_BODY_STREAM_EXHAUSTED': + return 'REQUEST_BODY_STREAM_EXHAUSTED'; + case 'RESET': + return 'RESET'; + case 'RESOURCE_UNAVAILABLE': + return 'RESOURCE_UNAVAILABLE'; + case 'SECURE_CONNECTION_FAILED': + return 'SECURE_CONNECTION_FAILED'; + case 'SERVER_CERTIFICATE_HAS_BAD_DATE': + return 'SERVER_CERTIFICATE_HAS_BAD_DATE'; + case 'SERVER_CERTIFICATE_HAS_UNKNOWN_ROOT': + return 'SERVER_CERTIFICATE_HAS_UNKNOWN_ROOT'; + case 'SERVER_CERTIFICATE_NOT_YET_VALID': + return 'SERVER_CERTIFICATE_NOT_YET_VALID'; + case 'SERVER_CERTIFICATE_UNTRUSTED': + return 'SERVER_CERTIFICATE_UNTRUSTED'; + case 'SERVER_UNREACHABLE': + return 'SERVER_UNREACHABLE'; + case 'TIMEOUT': + return 'TIMEOUT'; + case 'TOO_MANY_REDIRECTS': + return 'TOO_MANY_REDIRECTS'; + case 'TOO_MANY_REQUESTS': + return 'TOO_MANY_REQUESTS'; + case 'UNEXPECTED_ERROR': + return 'UNEXPECTED_ERROR'; + case 'UNKNOWN': + return 'UNKNOWN'; + case 'UNSAFE_RESOURCE': + return 'UNSAFE_RESOURCE'; + case 'UNSUPPORTED_AUTH_SCHEME': + return 'UNSUPPORTED_AUTH_SCHEME'; + case 'UNSUPPORTED_SCHEME': + return 'UNSUPPORTED_SCHEME'; + case 'USER_AUTHENTICATION_FAILED': + return 'USER_AUTHENTICATION_FAILED'; + case 'USER_AUTHENTICATION_REQUIRED': + return 'USER_AUTHENTICATION_REQUIRED'; + case 'USER_CANCELLED_AUTHENTICATION': + return 'USER_CANCELLED_AUTHENTICATION'; + case 'VALID_PROXY_AUTHENTICATION_REQUIRED': + return 'VALID_PROXY_AUTHENTICATION_REQUIRED'; + case 'ZERO_BYTE_RESOURCE': + return 'ZERO_BYTE_RESOURCE'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + @override String toString() { return _value; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/web_resource_request.dart b/flutter_inappwebview_platform_interface/lib/src/types/web_resource_request.dart index f92abb1a9..8d626b472 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/web_resource_request.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/web_resource_request.dart @@ -1,6 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import '../web_uri.dart'; +import 'enum_method.dart'; part 'web_resource_request.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/web_resource_request.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/web_resource_request.g.dart index 1ba292dff..449de39c6 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/web_resource_request.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/web_resource_request.g.dart @@ -47,7 +47,8 @@ class WebResourceRequest { required this.url}); ///Gets a possible [WebResourceRequest] instance from a [Map] value. - static WebResourceRequest? fromMap(Map? map) { + static WebResourceRequest? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -63,7 +64,7 @@ class WebResourceRequest { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "hasGesture": hasGesture, "headers": headers, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/web_resource_response.dart b/flutter_inappwebview_platform_interface/lib/src/types/web_resource_response.dart index 8df388d38..680c97e0f 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/web_resource_response.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/web_resource_response.dart @@ -1,7 +1,8 @@ import 'dart:typed_data'; - import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; +import 'enum_method.dart'; + part 'web_resource_response.g.dart'; ///Class representing a resource response of the `WebView`. diff --git a/flutter_inappwebview_platform_interface/lib/src/types/web_resource_response.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/web_resource_response.g.dart index 78ae7add3..9546a13e4 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/web_resource_response.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/web_resource_response.g.dart @@ -42,7 +42,8 @@ class WebResourceResponse { this.statusCode}); ///Gets a possible [WebResourceResponse] instance from a [Map] value. - static WebResourceResponse? fromMap(Map? map) { + static WebResourceResponse? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -60,7 +61,7 @@ class WebResourceResponse { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "contentEncoding": contentEncoding, "contentType": contentType, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/web_storage_origin.dart b/flutter_inappwebview_platform_interface/lib/src/types/web_storage_origin.dart index 2a532c7db..8e458fe40 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/web_storage_origin.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/web_storage_origin.dart @@ -1,6 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import '../web_storage/platform_web_storage_manager.dart'; +import 'enum_method.dart'; part 'web_storage_origin.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/web_storage_origin.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/web_storage_origin.g.dart index 11178c70b..74aaf01f3 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/web_storage_origin.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/web_storage_origin.g.dart @@ -20,7 +20,8 @@ class WebStorageOrigin { WebStorageOrigin({this.origin, this.quota, this.usage}); ///Gets a possible [WebStorageOrigin] instance from a [Map] value. - static WebStorageOrigin? fromMap(Map? map) { + static WebStorageOrigin? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -33,7 +34,7 @@ class WebStorageOrigin { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "origin": origin, "quota": quota, @@ -68,7 +69,8 @@ class AndroidWebStorageOrigin { AndroidWebStorageOrigin({this.origin, this.quota, this.usage}); ///Gets a possible [AndroidWebStorageOrigin] instance from a [Map] value. - static AndroidWebStorageOrigin? fromMap(Map? map) { + static AndroidWebStorageOrigin? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -81,7 +83,7 @@ class AndroidWebStorageOrigin { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "origin": origin, "quota": quota, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/web_storage_type.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/web_storage_type.g.dart index 2e53815ae..78278f313 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/web_storage_type.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/web_storage_type.g.dart @@ -58,18 +58,63 @@ class WebStorageType { return null; } + /// Gets a possible [WebStorageType] instance value with name [name]. + /// + /// Goes through [WebStorageType.values] looking for a value with + /// name [name], as reported by [WebStorageType.name]. + /// Returns the first value with the given name, otherwise `null`. + static WebStorageType? byName(String? name) { + if (name != null) { + try { + return WebStorageType.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [WebStorageType] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in WebStorageType.values) value.name(): value + }; + ///Gets [String] value. String toValue() => _value; ///Gets [String] native value. String toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'localStorage': + return 'LOCAL_STORAGE'; + case 'sessionStorage': + return 'SESSION_STORAGE'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { return _value; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/website_data_record.dart b/flutter_inappwebview_platform_interface/lib/src/types/website_data_record.dart index 90ed353c8..4495e4f90 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/website_data_record.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/website_data_record.dart @@ -1,6 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import 'website_data_type.dart'; +import 'enum_method.dart'; part 'website_data_record.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/website_data_record.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/website_data_record.g.dart index fb9a1f3ae..d40a3af01 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/website_data_record.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/website_data_record.g.dart @@ -16,14 +16,20 @@ class WebsiteDataRecord { WebsiteDataRecord({this.dataTypes, this.displayName}); ///Gets a possible [WebsiteDataRecord] instance from a [Map] value. - static WebsiteDataRecord? fromMap(Map? map) { + static WebsiteDataRecord? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = WebsiteDataRecord( dataTypes: map['dataTypes'] != null - ? Set.from( - map['dataTypes'].map((e) => WebsiteDataType.fromNativeValue(e)!)) + ? Set.from(map['dataTypes'] + .map((e) => switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + WebsiteDataType.fromNativeValue(e), + EnumMethod.value => WebsiteDataType.fromValue(e), + EnumMethod.name => WebsiteDataType.byName(e) + }!)) : null, displayName: map['displayName'], ); @@ -31,9 +37,15 @@ class WebsiteDataRecord { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "dataTypes": dataTypes?.map((e) => e.toNativeValue()).toList(), + "dataTypes": dataTypes + ?.map((e) => switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => e.toNativeValue(), + EnumMethod.value => e.toValue(), + EnumMethod.name => e.name() + }) + .toList(), "displayName": displayName, }; } @@ -64,14 +76,20 @@ class IOSWKWebsiteDataRecord { IOSWKWebsiteDataRecord({this.dataTypes, this.displayName}); ///Gets a possible [IOSWKWebsiteDataRecord] instance from a [Map] value. - static IOSWKWebsiteDataRecord? fromMap(Map? map) { + static IOSWKWebsiteDataRecord? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } final instance = IOSWKWebsiteDataRecord( dataTypes: map['dataTypes'] != null ? Set.from(map['dataTypes'] - .map((e) => IOSWKWebsiteDataType.fromNativeValue(e)!)) + .map((e) => switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + IOSWKWebsiteDataType.fromNativeValue(e), + EnumMethod.value => IOSWKWebsiteDataType.fromValue(e), + EnumMethod.name => IOSWKWebsiteDataType.byName(e) + }!)) : null, displayName: map['displayName'], ); @@ -79,9 +97,15 @@ class IOSWKWebsiteDataRecord { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "dataTypes": dataTypes?.map((e) => e.toNativeValue()).toList(), + "dataTypes": dataTypes + ?.map((e) => switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => e.toNativeValue(), + EnumMethod.value => e.toValue(), + EnumMethod.name => e.name() + }) + .toList(), "displayName": displayName, }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/website_data_type.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/website_data_type.g.dart index e10da39dd..ca0692d28 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/website_data_type.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/website_data_type.g.dart @@ -117,18 +117,81 @@ class WebsiteDataType { return null; } + /// Gets a possible [WebsiteDataType] instance value with name [name]. + /// + /// Goes through [WebsiteDataType.values] looking for a value with + /// name [name], as reported by [WebsiteDataType.name]. + /// Returns the first value with the given name, otherwise `null`. + static WebsiteDataType? byName(String? name) { + if (name != null) { + try { + return WebsiteDataType.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [WebsiteDataType] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in WebsiteDataType.values) value.name(): value + }; + ///Gets [String] value. String toValue() => _value; ///Gets [String] native value. String toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'null': + return 'ALL'; + case 'WKWebsiteDataTypeCookies': + return 'WKWebsiteDataTypeCookies'; + case 'WKWebsiteDataTypeDiskCache': + return 'WKWebsiteDataTypeDiskCache'; + case 'WKWebsiteDataTypeFetchCache': + return 'WKWebsiteDataTypeFetchCache'; + case 'WKWebsiteDataTypeIndexedDBDatabases': + return 'WKWebsiteDataTypeIndexedDBDatabases'; + case 'WKWebsiteDataTypeLocalStorage': + return 'WKWebsiteDataTypeLocalStorage'; + case 'WKWebsiteDataTypeMemoryCache': + return 'WKWebsiteDataTypeMemoryCache'; + case 'WKWebsiteDataTypeOfflineWebApplicationCache': + return 'WKWebsiteDataTypeOfflineWebApplicationCache'; + case 'WKWebsiteDataTypeServiceWorkerRegistrations': + return 'WKWebsiteDataTypeServiceWorkerRegistrations'; + case 'WKWebsiteDataTypeSessionStorage': + return 'WKWebsiteDataTypeSessionStorage'; + case 'WKWebsiteDataTypeWebSQLDatabases': + return 'WKWebsiteDataTypeWebSQLDatabases'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { return _value; @@ -254,18 +317,82 @@ class IOSWKWebsiteDataType { return null; } + /// Gets a possible [IOSWKWebsiteDataType] instance value with name [name]. + /// + /// Goes through [IOSWKWebsiteDataType.values] looking for a value with + /// name [name], as reported by [IOSWKWebsiteDataType.name]. + /// Returns the first value with the given name, otherwise `null`. + static IOSWKWebsiteDataType? byName(String? name) { + if (name != null) { + try { + return IOSWKWebsiteDataType.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [IOSWKWebsiteDataType] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in IOSWKWebsiteDataType.values) value.name(): value + }; + ///Gets [String] value. String toValue() => _value; ///Gets [String] native value. String toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'null': + return 'ALL'; + case 'WKWebsiteDataTypeCookies': + return 'WKWebsiteDataTypeCookies'; + case 'WKWebsiteDataTypeDiskCache': + return 'WKWebsiteDataTypeDiskCache'; + case 'WKWebsiteDataTypeFetchCache': + return 'WKWebsiteDataTypeFetchCache'; + case 'WKWebsiteDataTypeIndexedDBDatabases': + return 'WKWebsiteDataTypeIndexedDBDatabases'; + case 'WKWebsiteDataTypeLocalStorage': + return 'WKWebsiteDataTypeLocalStorage'; + case 'WKWebsiteDataTypeMemoryCache': + return 'WKWebsiteDataTypeMemoryCache'; + case 'WKWebsiteDataTypeOfflineWebApplicationCache': + return 'WKWebsiteDataTypeOfflineWebApplicationCache'; + case 'WKWebsiteDataTypeServiceWorkerRegistrations': + return 'WKWebsiteDataTypeServiceWorkerRegistrations'; + case 'WKWebsiteDataTypeSessionStorage': + return 'WKWebsiteDataTypeSessionStorage'; + case 'WKWebsiteDataTypeWebSQLDatabases': + return 'WKWebsiteDataTypeWebSQLDatabases'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { return _value; diff --git a/flutter_inappwebview_platform_interface/lib/src/types/webview_interface.dart b/flutter_inappwebview_platform_interface/lib/src/types/webview_interface.dart new file mode 100644 index 000000000..76e7bca5a --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/webview_interface.dart @@ -0,0 +1,130 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +part 'webview_interface.g.dart'; + +///Class that represents the interfaces that a WebView can support. +@ExchangeableEnum() +class WebViewInterface_ { + // ignore: unused_field + final String _value; + const WebViewInterface_._internal(this._value); + + static const ICoreWebView2Environment = + const WebViewInterface_._internal("ICoreWebView2Environment"); + static const ICoreWebView2Environment2 = + const WebViewInterface_._internal("ICoreWebView2Environment2"); + static const ICoreWebView2Environment3 = + const WebViewInterface_._internal("ICoreWebView2Environment3"); + static const ICoreWebView2Environment4 = + const WebViewInterface_._internal("ICoreWebView2Environment4"); + static const ICoreWebView2Environment5 = + const WebViewInterface_._internal("ICoreWebView2Environment5"); + static const ICoreWebView2Environment6 = + const WebViewInterface_._internal("ICoreWebView2Environment6"); + static const ICoreWebView2Environment7 = + const WebViewInterface_._internal("ICoreWebView2Environment7"); + static const ICoreWebView2Environment8 = + const WebViewInterface_._internal("ICoreWebView2Environment8"); + static const ICoreWebView2Environment9 = + const WebViewInterface_._internal("ICoreWebView2Environment9"); + static const ICoreWebView2Environment10 = + const WebViewInterface_._internal("ICoreWebView2Environment10"); + static const ICoreWebView2Environment11 = + const WebViewInterface_._internal("ICoreWebView2Environment11"); + static const ICoreWebView2Environment12 = + const WebViewInterface_._internal("ICoreWebView2Environment12"); + static const ICoreWebView2Environment13 = + const WebViewInterface_._internal("ICoreWebView2Environment13"); + static const ICoreWebView2Environment14 = + const WebViewInterface_._internal("ICoreWebView2Environment14"); + + static const ICoreWebView2Controller = + const WebViewInterface_._internal("ICoreWebView2Controller"); + static const ICoreWebView2Controller2 = + const WebViewInterface_._internal("ICoreWebView2Controller2"); + static const ICoreWebView2Controller3 = + const WebViewInterface_._internal("ICoreWebView2Controller3"); + static const ICoreWebView2Controller4 = + const WebViewInterface_._internal("ICoreWebView2Controller4"); + + static const ICoreWebView2CompositionController = + const WebViewInterface_._internal("ICoreWebView2CompositionController"); + static const ICoreWebView2CompositionController2 = + const WebViewInterface_._internal("ICoreWebView2CompositionController2"); + static const ICoreWebView2CompositionController3 = + const WebViewInterface_._internal("ICoreWebView2CompositionController3"); + static const ICoreWebView2CompositionController4 = + const WebViewInterface_._internal("ICoreWebView2CompositionController4"); + + static const ICoreWebView2 = + const WebViewInterface_._internal("ICoreWebView2"); + static const ICoreWebView2_2 = + const WebViewInterface_._internal("ICoreWebView2_2"); + static const ICoreWebView2_3 = + const WebViewInterface_._internal("ICoreWebView2_3"); + static const ICoreWebView2_4 = + const WebViewInterface_._internal("ICoreWebView2_4"); + static const ICoreWebView2_5 = + const WebViewInterface_._internal("ICoreWebView2_5"); + static const ICoreWebView2_6 = + const WebViewInterface_._internal("ICoreWebView2_6"); + static const ICoreWebView2_7 = + const WebViewInterface_._internal("ICoreWebView2_7"); + static const ICoreWebView2_8 = + const WebViewInterface_._internal("ICoreWebView2_8"); + static const ICoreWebView2_9 = + const WebViewInterface_._internal("ICoreWebView2_9"); + static const ICoreWebView2_10 = + const WebViewInterface_._internal("ICoreWebView2_10"); + static const ICoreWebView2_11 = + const WebViewInterface_._internal("ICoreWebView2_11"); + static const ICoreWebView2_12 = + const WebViewInterface_._internal("ICoreWebView2_12"); + static const ICoreWebView2_13 = + const WebViewInterface_._internal("ICoreWebView2_13"); + static const ICoreWebView2_14 = + const WebViewInterface_._internal("ICoreWebView2_14"); + static const ICoreWebView2_15 = + const WebViewInterface_._internal("ICoreWebView2_15"); + static const ICoreWebView2_16 = + const WebViewInterface_._internal("ICoreWebView2_16"); + static const ICoreWebView2_17 = + const WebViewInterface_._internal("ICoreWebView2_17"); + static const ICoreWebView2_18 = + const WebViewInterface_._internal("ICoreWebView2_18"); + static const ICoreWebView2_19 = + const WebViewInterface_._internal("ICoreWebView2_19"); + static const ICoreWebView2_20 = + const WebViewInterface_._internal("ICoreWebView2_20"); + static const ICoreWebView2_21 = + const WebViewInterface_._internal("ICoreWebView2_21"); + static const ICoreWebView2_22 = + const WebViewInterface_._internal("ICoreWebView2_22"); + static const ICoreWebView2_23 = + const WebViewInterface_._internal("ICoreWebView2_23"); + static const ICoreWebView2_24 = + const WebViewInterface_._internal("ICoreWebView2_24"); + static const ICoreWebView2_25 = + const WebViewInterface_._internal("ICoreWebView2_25"); + static const ICoreWebView2_26 = + const WebViewInterface_._internal("ICoreWebView2_26"); + + static const ICoreWebView2Settings = + const WebViewInterface_._internal("ICoreWebView2Settings"); + static const ICoreWebView2Settings2 = + const WebViewInterface_._internal("ICoreWebView2Settings2"); + static const ICoreWebView2Settings3 = + const WebViewInterface_._internal("ICoreWebView2Settings3"); + static const ICoreWebView2Settings4 = + const WebViewInterface_._internal("ICoreWebView2Settings4"); + static const ICoreWebView2Settings5 = + const WebViewInterface_._internal("ICoreWebView2Settings5"); + static const ICoreWebView2Settings6 = + const WebViewInterface_._internal("ICoreWebView2Settings6"); + static const ICoreWebView2Settings7 = + const WebViewInterface_._internal("ICoreWebView2Settings7"); + static const ICoreWebView2Settings8 = + const WebViewInterface_._internal("ICoreWebView2Settings8"); + static const ICoreWebView2Settings9 = + const WebViewInterface_._internal("ICoreWebView2Settings9"); +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/webview_interface.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/webview_interface.g.dart new file mode 100644 index 000000000..25888210f --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/types/webview_interface.g.dart @@ -0,0 +1,396 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'webview_interface.dart'; + +// ************************************************************************** +// ExchangeableEnumGenerator +// ************************************************************************** + +///Class that represents the interfaces that a WebView can support. +class WebViewInterface { + final String _value; + final String _nativeValue; + const WebViewInterface._internal(this._value, this._nativeValue); +// ignore: unused_element + factory WebViewInterface._internalMultiPlatform( + String value, Function nativeValue) => + WebViewInterface._internal(value, nativeValue()); + static const ICoreWebView2 = + WebViewInterface._internal('ICoreWebView2', 'ICoreWebView2'); + static const ICoreWebView2CompositionController = WebViewInterface._internal( + 'ICoreWebView2CompositionController', + 'ICoreWebView2CompositionController'); + static const ICoreWebView2CompositionController2 = WebViewInterface._internal( + 'ICoreWebView2CompositionController2', + 'ICoreWebView2CompositionController2'); + static const ICoreWebView2CompositionController3 = WebViewInterface._internal( + 'ICoreWebView2CompositionController3', + 'ICoreWebView2CompositionController3'); + static const ICoreWebView2CompositionController4 = WebViewInterface._internal( + 'ICoreWebView2CompositionController4', + 'ICoreWebView2CompositionController4'); + static const ICoreWebView2Controller = WebViewInterface._internal( + 'ICoreWebView2Controller', 'ICoreWebView2Controller'); + static const ICoreWebView2Controller2 = WebViewInterface._internal( + 'ICoreWebView2Controller2', 'ICoreWebView2Controller2'); + static const ICoreWebView2Controller3 = WebViewInterface._internal( + 'ICoreWebView2Controller3', 'ICoreWebView2Controller3'); + static const ICoreWebView2Controller4 = WebViewInterface._internal( + 'ICoreWebView2Controller4', 'ICoreWebView2Controller4'); + static const ICoreWebView2Environment = WebViewInterface._internal( + 'ICoreWebView2Environment', 'ICoreWebView2Environment'); + static const ICoreWebView2Environment10 = WebViewInterface._internal( + 'ICoreWebView2Environment10', 'ICoreWebView2Environment10'); + static const ICoreWebView2Environment11 = WebViewInterface._internal( + 'ICoreWebView2Environment11', 'ICoreWebView2Environment11'); + static const ICoreWebView2Environment12 = WebViewInterface._internal( + 'ICoreWebView2Environment12', 'ICoreWebView2Environment12'); + static const ICoreWebView2Environment13 = WebViewInterface._internal( + 'ICoreWebView2Environment13', 'ICoreWebView2Environment13'); + static const ICoreWebView2Environment14 = WebViewInterface._internal( + 'ICoreWebView2Environment14', 'ICoreWebView2Environment14'); + static const ICoreWebView2Environment2 = WebViewInterface._internal( + 'ICoreWebView2Environment2', 'ICoreWebView2Environment2'); + static const ICoreWebView2Environment3 = WebViewInterface._internal( + 'ICoreWebView2Environment3', 'ICoreWebView2Environment3'); + static const ICoreWebView2Environment4 = WebViewInterface._internal( + 'ICoreWebView2Environment4', 'ICoreWebView2Environment4'); + static const ICoreWebView2Environment5 = WebViewInterface._internal( + 'ICoreWebView2Environment5', 'ICoreWebView2Environment5'); + static const ICoreWebView2Environment6 = WebViewInterface._internal( + 'ICoreWebView2Environment6', 'ICoreWebView2Environment6'); + static const ICoreWebView2Environment7 = WebViewInterface._internal( + 'ICoreWebView2Environment7', 'ICoreWebView2Environment7'); + static const ICoreWebView2Environment8 = WebViewInterface._internal( + 'ICoreWebView2Environment8', 'ICoreWebView2Environment8'); + static const ICoreWebView2Environment9 = WebViewInterface._internal( + 'ICoreWebView2Environment9', 'ICoreWebView2Environment9'); + static const ICoreWebView2Settings = WebViewInterface._internal( + 'ICoreWebView2Settings', 'ICoreWebView2Settings'); + static const ICoreWebView2Settings2 = WebViewInterface._internal( + 'ICoreWebView2Settings2', 'ICoreWebView2Settings2'); + static const ICoreWebView2Settings3 = WebViewInterface._internal( + 'ICoreWebView2Settings3', 'ICoreWebView2Settings3'); + static const ICoreWebView2Settings4 = WebViewInterface._internal( + 'ICoreWebView2Settings4', 'ICoreWebView2Settings4'); + static const ICoreWebView2Settings5 = WebViewInterface._internal( + 'ICoreWebView2Settings5', 'ICoreWebView2Settings5'); + static const ICoreWebView2Settings6 = WebViewInterface._internal( + 'ICoreWebView2Settings6', 'ICoreWebView2Settings6'); + static const ICoreWebView2Settings7 = WebViewInterface._internal( + 'ICoreWebView2Settings7', 'ICoreWebView2Settings7'); + static const ICoreWebView2Settings8 = WebViewInterface._internal( + 'ICoreWebView2Settings8', 'ICoreWebView2Settings8'); + static const ICoreWebView2Settings9 = WebViewInterface._internal( + 'ICoreWebView2Settings9', 'ICoreWebView2Settings9'); + static const ICoreWebView2_10 = + WebViewInterface._internal('ICoreWebView2_10', 'ICoreWebView2_10'); + static const ICoreWebView2_11 = + WebViewInterface._internal('ICoreWebView2_11', 'ICoreWebView2_11'); + static const ICoreWebView2_12 = + WebViewInterface._internal('ICoreWebView2_12', 'ICoreWebView2_12'); + static const ICoreWebView2_13 = + WebViewInterface._internal('ICoreWebView2_13', 'ICoreWebView2_13'); + static const ICoreWebView2_14 = + WebViewInterface._internal('ICoreWebView2_14', 'ICoreWebView2_14'); + static const ICoreWebView2_15 = + WebViewInterface._internal('ICoreWebView2_15', 'ICoreWebView2_15'); + static const ICoreWebView2_16 = + WebViewInterface._internal('ICoreWebView2_16', 'ICoreWebView2_16'); + static const ICoreWebView2_17 = + WebViewInterface._internal('ICoreWebView2_17', 'ICoreWebView2_17'); + static const ICoreWebView2_18 = + WebViewInterface._internal('ICoreWebView2_18', 'ICoreWebView2_18'); + static const ICoreWebView2_19 = + WebViewInterface._internal('ICoreWebView2_19', 'ICoreWebView2_19'); + static const ICoreWebView2_2 = + WebViewInterface._internal('ICoreWebView2_2', 'ICoreWebView2_2'); + static const ICoreWebView2_20 = + WebViewInterface._internal('ICoreWebView2_20', 'ICoreWebView2_20'); + static const ICoreWebView2_21 = + WebViewInterface._internal('ICoreWebView2_21', 'ICoreWebView2_21'); + static const ICoreWebView2_22 = + WebViewInterface._internal('ICoreWebView2_22', 'ICoreWebView2_22'); + static const ICoreWebView2_23 = + WebViewInterface._internal('ICoreWebView2_23', 'ICoreWebView2_23'); + static const ICoreWebView2_24 = + WebViewInterface._internal('ICoreWebView2_24', 'ICoreWebView2_24'); + static const ICoreWebView2_25 = + WebViewInterface._internal('ICoreWebView2_25', 'ICoreWebView2_25'); + static const ICoreWebView2_26 = + WebViewInterface._internal('ICoreWebView2_26', 'ICoreWebView2_26'); + static const ICoreWebView2_3 = + WebViewInterface._internal('ICoreWebView2_3', 'ICoreWebView2_3'); + static const ICoreWebView2_4 = + WebViewInterface._internal('ICoreWebView2_4', 'ICoreWebView2_4'); + static const ICoreWebView2_5 = + WebViewInterface._internal('ICoreWebView2_5', 'ICoreWebView2_5'); + static const ICoreWebView2_6 = + WebViewInterface._internal('ICoreWebView2_6', 'ICoreWebView2_6'); + static const ICoreWebView2_7 = + WebViewInterface._internal('ICoreWebView2_7', 'ICoreWebView2_7'); + static const ICoreWebView2_8 = + WebViewInterface._internal('ICoreWebView2_8', 'ICoreWebView2_8'); + static const ICoreWebView2_9 = + WebViewInterface._internal('ICoreWebView2_9', 'ICoreWebView2_9'); + + ///Set of all values of [WebViewInterface]. + static final Set values = [ + WebViewInterface.ICoreWebView2, + WebViewInterface.ICoreWebView2CompositionController, + WebViewInterface.ICoreWebView2CompositionController2, + WebViewInterface.ICoreWebView2CompositionController3, + WebViewInterface.ICoreWebView2CompositionController4, + WebViewInterface.ICoreWebView2Controller, + WebViewInterface.ICoreWebView2Controller2, + WebViewInterface.ICoreWebView2Controller3, + WebViewInterface.ICoreWebView2Controller4, + WebViewInterface.ICoreWebView2Environment, + WebViewInterface.ICoreWebView2Environment10, + WebViewInterface.ICoreWebView2Environment11, + WebViewInterface.ICoreWebView2Environment12, + WebViewInterface.ICoreWebView2Environment13, + WebViewInterface.ICoreWebView2Environment14, + WebViewInterface.ICoreWebView2Environment2, + WebViewInterface.ICoreWebView2Environment3, + WebViewInterface.ICoreWebView2Environment4, + WebViewInterface.ICoreWebView2Environment5, + WebViewInterface.ICoreWebView2Environment6, + WebViewInterface.ICoreWebView2Environment7, + WebViewInterface.ICoreWebView2Environment8, + WebViewInterface.ICoreWebView2Environment9, + WebViewInterface.ICoreWebView2Settings, + WebViewInterface.ICoreWebView2Settings2, + WebViewInterface.ICoreWebView2Settings3, + WebViewInterface.ICoreWebView2Settings4, + WebViewInterface.ICoreWebView2Settings5, + WebViewInterface.ICoreWebView2Settings6, + WebViewInterface.ICoreWebView2Settings7, + WebViewInterface.ICoreWebView2Settings8, + WebViewInterface.ICoreWebView2Settings9, + WebViewInterface.ICoreWebView2_10, + WebViewInterface.ICoreWebView2_11, + WebViewInterface.ICoreWebView2_12, + WebViewInterface.ICoreWebView2_13, + WebViewInterface.ICoreWebView2_14, + WebViewInterface.ICoreWebView2_15, + WebViewInterface.ICoreWebView2_16, + WebViewInterface.ICoreWebView2_17, + WebViewInterface.ICoreWebView2_18, + WebViewInterface.ICoreWebView2_19, + WebViewInterface.ICoreWebView2_2, + WebViewInterface.ICoreWebView2_20, + WebViewInterface.ICoreWebView2_21, + WebViewInterface.ICoreWebView2_22, + WebViewInterface.ICoreWebView2_23, + WebViewInterface.ICoreWebView2_24, + WebViewInterface.ICoreWebView2_25, + WebViewInterface.ICoreWebView2_26, + WebViewInterface.ICoreWebView2_3, + WebViewInterface.ICoreWebView2_4, + WebViewInterface.ICoreWebView2_5, + WebViewInterface.ICoreWebView2_6, + WebViewInterface.ICoreWebView2_7, + WebViewInterface.ICoreWebView2_8, + WebViewInterface.ICoreWebView2_9, + ].toSet(); + + ///Gets a possible [WebViewInterface] instance from [String] value. + static WebViewInterface? fromValue(String? value) { + if (value != null) { + try { + return WebViewInterface.values + .firstWhere((element) => element.toValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + ///Gets a possible [WebViewInterface] instance from a native value. + static WebViewInterface? fromNativeValue(String? value) { + if (value != null) { + try { + return WebViewInterface.values + .firstWhere((element) => element.toNativeValue() == value); + } catch (e) { + return null; + } + } + return null; + } + + /// Gets a possible [WebViewInterface] instance value with name [name]. + /// + /// Goes through [WebViewInterface.values] looking for a value with + /// name [name], as reported by [WebViewInterface.name]. + /// Returns the first value with the given name, otherwise `null`. + static WebViewInterface? byName(String? name) { + if (name != null) { + try { + return WebViewInterface.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [WebViewInterface] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in WebViewInterface.values) value.name(): value + }; + + ///Gets [String] value. + String toValue() => _value; + + ///Gets [String] native value. + String toNativeValue() => _nativeValue; + + ///Gets the name of the value. + String name() { + switch (_value) { + case 'ICoreWebView2': + return 'ICoreWebView2'; + case 'ICoreWebView2CompositionController': + return 'ICoreWebView2CompositionController'; + case 'ICoreWebView2CompositionController2': + return 'ICoreWebView2CompositionController2'; + case 'ICoreWebView2CompositionController3': + return 'ICoreWebView2CompositionController3'; + case 'ICoreWebView2CompositionController4': + return 'ICoreWebView2CompositionController4'; + case 'ICoreWebView2Controller': + return 'ICoreWebView2Controller'; + case 'ICoreWebView2Controller2': + return 'ICoreWebView2Controller2'; + case 'ICoreWebView2Controller3': + return 'ICoreWebView2Controller3'; + case 'ICoreWebView2Controller4': + return 'ICoreWebView2Controller4'; + case 'ICoreWebView2Environment': + return 'ICoreWebView2Environment'; + case 'ICoreWebView2Environment10': + return 'ICoreWebView2Environment10'; + case 'ICoreWebView2Environment11': + return 'ICoreWebView2Environment11'; + case 'ICoreWebView2Environment12': + return 'ICoreWebView2Environment12'; + case 'ICoreWebView2Environment13': + return 'ICoreWebView2Environment13'; + case 'ICoreWebView2Environment14': + return 'ICoreWebView2Environment14'; + case 'ICoreWebView2Environment2': + return 'ICoreWebView2Environment2'; + case 'ICoreWebView2Environment3': + return 'ICoreWebView2Environment3'; + case 'ICoreWebView2Environment4': + return 'ICoreWebView2Environment4'; + case 'ICoreWebView2Environment5': + return 'ICoreWebView2Environment5'; + case 'ICoreWebView2Environment6': + return 'ICoreWebView2Environment6'; + case 'ICoreWebView2Environment7': + return 'ICoreWebView2Environment7'; + case 'ICoreWebView2Environment8': + return 'ICoreWebView2Environment8'; + case 'ICoreWebView2Environment9': + return 'ICoreWebView2Environment9'; + case 'ICoreWebView2Settings': + return 'ICoreWebView2Settings'; + case 'ICoreWebView2Settings2': + return 'ICoreWebView2Settings2'; + case 'ICoreWebView2Settings3': + return 'ICoreWebView2Settings3'; + case 'ICoreWebView2Settings4': + return 'ICoreWebView2Settings4'; + case 'ICoreWebView2Settings5': + return 'ICoreWebView2Settings5'; + case 'ICoreWebView2Settings6': + return 'ICoreWebView2Settings6'; + case 'ICoreWebView2Settings7': + return 'ICoreWebView2Settings7'; + case 'ICoreWebView2Settings8': + return 'ICoreWebView2Settings8'; + case 'ICoreWebView2Settings9': + return 'ICoreWebView2Settings9'; + case 'ICoreWebView2_10': + return 'ICoreWebView2_10'; + case 'ICoreWebView2_11': + return 'ICoreWebView2_11'; + case 'ICoreWebView2_12': + return 'ICoreWebView2_12'; + case 'ICoreWebView2_13': + return 'ICoreWebView2_13'; + case 'ICoreWebView2_14': + return 'ICoreWebView2_14'; + case 'ICoreWebView2_15': + return 'ICoreWebView2_15'; + case 'ICoreWebView2_16': + return 'ICoreWebView2_16'; + case 'ICoreWebView2_17': + return 'ICoreWebView2_17'; + case 'ICoreWebView2_18': + return 'ICoreWebView2_18'; + case 'ICoreWebView2_19': + return 'ICoreWebView2_19'; + case 'ICoreWebView2_2': + return 'ICoreWebView2_2'; + case 'ICoreWebView2_20': + return 'ICoreWebView2_20'; + case 'ICoreWebView2_21': + return 'ICoreWebView2_21'; + case 'ICoreWebView2_22': + return 'ICoreWebView2_22'; + case 'ICoreWebView2_23': + return 'ICoreWebView2_23'; + case 'ICoreWebView2_24': + return 'ICoreWebView2_24'; + case 'ICoreWebView2_25': + return 'ICoreWebView2_25'; + case 'ICoreWebView2_26': + return 'ICoreWebView2_26'; + case 'ICoreWebView2_3': + return 'ICoreWebView2_3'; + case 'ICoreWebView2_4': + return 'ICoreWebView2_4'; + case 'ICoreWebView2_5': + return 'ICoreWebView2_5'; + case 'ICoreWebView2_6': + return 'ICoreWebView2_6'; + case 'ICoreWebView2_7': + return 'ICoreWebView2_7'; + case 'ICoreWebView2_8': + return 'ICoreWebView2_8'; + case 'ICoreWebView2_9': + return 'ICoreWebView2_9'; + } + return _value.toString(); + } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + + @override + String toString() { + return _value; + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/types/webview_package_info.dart b/flutter_inappwebview_platform_interface/lib/src/types/webview_package_info.dart index ec5985d15..8940a25e3 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/webview_package_info.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/webview_package_info.dart @@ -1,5 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; +import 'enum_method.dart'; + part 'webview_package_info.g.dart'; ///Class that represents a `WebView` package info. diff --git a/flutter_inappwebview_platform_interface/lib/src/types/webview_package_info.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/webview_package_info.g.dart index e1b2c3e8c..22fb70ec6 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/webview_package_info.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/webview_package_info.g.dart @@ -16,7 +16,8 @@ class WebViewPackageInfo { WebViewPackageInfo({this.packageName, this.versionName}); ///Gets a possible [WebViewPackageInfo] instance from a [Map] value. - static WebViewPackageInfo? fromMap(Map? map) { + static WebViewPackageInfo? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -28,7 +29,7 @@ class WebViewPackageInfo { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "packageName": packageName, "versionName": versionName, @@ -58,7 +59,8 @@ class AndroidWebViewPackageInfo { AndroidWebViewPackageInfo({this.packageName, this.versionName}); ///Gets a possible [AndroidWebViewPackageInfo] instance from a [Map] value. - static AndroidWebViewPackageInfo? fromMap(Map? map) { + static AndroidWebViewPackageInfo? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -70,7 +72,7 @@ class AndroidWebViewPackageInfo { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "packageName": packageName, "versionName": versionName, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/webview_render_process_action.dart b/flutter_inappwebview_platform_interface/lib/src/types/webview_render_process_action.dart index 1fca268bf..f88d02916 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/webview_render_process_action.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/webview_render_process_action.dart @@ -11,5 +11,8 @@ class WebViewRenderProcessAction_ { const WebViewRenderProcessAction_._internal(this._value); ///Cause this renderer to terminate. + @EnumSupportedPlatforms(platforms: [ + EnumAndroidPlatform(), + ]) static const TERMINATE = const WebViewRenderProcessAction_._internal(0); } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/webview_render_process_action.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/webview_render_process_action.g.dart index 15542077b..d2ae3753b 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/webview_render_process_action.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/webview_render_process_action.g.dart @@ -18,6 +18,9 @@ class WebViewRenderProcessAction { WebViewRenderProcessAction._internal(value, nativeValue()); ///Cause this renderer to terminate. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView static const TERMINATE = WebViewRenderProcessAction._internal(0, 0); ///Set of all values of [WebViewRenderProcessAction]. @@ -51,24 +54,65 @@ class WebViewRenderProcessAction { return null; } + /// Gets a possible [WebViewRenderProcessAction] instance value with name [name]. + /// + /// Goes through [WebViewRenderProcessAction.values] looking for a value with + /// name [name], as reported by [WebViewRenderProcessAction.name]. + /// Returns the first value with the given name, otherwise `null`. + static WebViewRenderProcessAction? byName(String? name) { + if (name != null) { + try { + return WebViewRenderProcessAction.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [WebViewRenderProcessAction] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in WebViewRenderProcessAction.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 0: + return 'TERMINATE'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + @override String toString() { - switch (_value) { - case 0: - return 'TERMINATE'; - } - return _value.toString(); + return name(); } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/window_features.dart b/flutter_inappwebview_platform_interface/lib/src/types/window_features.dart index 9b72119f7..deba724d0 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/window_features.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/window_features.dart @@ -1,5 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; +import 'enum_method.dart'; + part 'window_features.g.dart'; ///Class that specifies optional attributes for the containing window when a new web view is requested. diff --git a/flutter_inappwebview_platform_interface/lib/src/types/window_features.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/window_features.g.dart index 431416053..248d7a9c3 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/window_features.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/window_features.g.dart @@ -42,7 +42,8 @@ class WindowFeatures { this.y}); ///Gets a possible [WindowFeatures] instance from a [Map] value. - static WindowFeatures? fromMap(Map? map) { + static WindowFeatures? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -60,7 +61,7 @@ class WindowFeatures { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "allowsResizing": allowsResizing, "height": height, @@ -122,7 +123,8 @@ class IOSWKWindowFeatures { this.y}); ///Gets a possible [IOSWKWindowFeatures] instance from a [Map] value. - static IOSWKWindowFeatures? fromMap(Map? map) { + static IOSWKWindowFeatures? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -140,7 +142,7 @@ class IOSWKWindowFeatures { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "allowsResizing": allowsResizing, "height": height, diff --git a/flutter_inappwebview_platform_interface/lib/src/types/window_style_mask.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/window_style_mask.g.dart index cde3470c2..c9ad9ccd3 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/window_style_mask.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/window_style_mask.g.dart @@ -19,7 +19,7 @@ class WindowStyleMask { ///The window displays none of the usual peripheral elements. Useful only for display or caching purposes. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS ([Official API - NSWindow.StyleMask.borderless](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644698-borderless)) + ///- macOS WKWebView ([Official API - NSWindow.StyleMask.borderless](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644698-borderless)) static final BORDERLESS = WindowStyleMask._internalMultiPlatform(0, () { switch (defaultTargetPlatform) { case TargetPlatform.macOS: @@ -33,7 +33,7 @@ class WindowStyleMask { ///The window displays a close button. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS ([Official API - NSWindow.StyleMask.closable](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644610-closable)) + ///- macOS WKWebView ([Official API - NSWindow.StyleMask.closable](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644610-closable)) static final CLOSABLE = WindowStyleMask._internalMultiPlatform(2, () { switch (defaultTargetPlatform) { case TargetPlatform.macOS: @@ -47,7 +47,7 @@ class WindowStyleMask { ///The window is a document-modal panel. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS ([Official API - NSWindow.StyleMask.docModalWindow](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644253-docmodalwindow)) + ///- macOS WKWebView ([Official API - NSWindow.StyleMask.docModalWindow](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644253-docmodalwindow)) static final DOC_MODAL_WINDOW = WindowStyleMask._internalMultiPlatform(64, () { switch (defaultTargetPlatform) { @@ -62,7 +62,7 @@ class WindowStyleMask { ///The window can appear full screen. A fullscreen window does not draw its title bar, and may have special handling for its toolbar. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS ([Official API - NSWindow.StyleMask.fullScreen](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644530-fullscreen)) + ///- macOS WKWebView ([Official API - NSWindow.StyleMask.fullScreen](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644530-fullscreen)) static final FULLSCREEN = WindowStyleMask._internalMultiPlatform(16384, () { switch (defaultTargetPlatform) { case TargetPlatform.macOS: @@ -78,7 +78,7 @@ class WindowStyleMask { ///Note that using this mask opts in to layer-backing. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS ([Official API - NSWindow.StyleMask.fullSizeContentView](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644646-fullsizecontentview)) + ///- macOS WKWebView ([Official API - NSWindow.StyleMask.fullSizeContentView](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644646-fullsizecontentview)) static final FULL_SIZE_CONTENT_VIEW = WindowStyleMask._internalMultiPlatform(32768, () { switch (defaultTargetPlatform) { @@ -93,7 +93,7 @@ class WindowStyleMask { ///The window is a HUD panel. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS ([Official API - NSWindow.StyleMask.hudWindow](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644653-hudwindow)) + ///- macOS WKWebView ([Official API - NSWindow.StyleMask.hudWindow](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644653-hudwindow)) static final HUD_WINDOW = WindowStyleMask._internalMultiPlatform(8192, () { switch (defaultTargetPlatform) { case TargetPlatform.macOS: @@ -107,7 +107,7 @@ class WindowStyleMask { ///The window displays a minimize button. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS ([Official API - NSWindow.StyleMask.miniaturizable](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644650-miniaturizable)) + ///- macOS WKWebView ([Official API - NSWindow.StyleMask.miniaturizable](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644650-miniaturizable)) static final MINIATURIZABLE = WindowStyleMask._internalMultiPlatform(4, () { switch (defaultTargetPlatform) { case TargetPlatform.macOS: @@ -121,7 +121,7 @@ class WindowStyleMask { ///The window is a panel that does not activate the owning app. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS ([Official API - NSWindow.StyleMask.nonactivatingPanel](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644696-nonactivatingpanel)) + ///- macOS WKWebView ([Official API - NSWindow.StyleMask.nonactivatingPanel](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644696-nonactivatingpanel)) static final NONACTIVATING_PANEL = WindowStyleMask._internalMultiPlatform(128, () { switch (defaultTargetPlatform) { @@ -136,7 +136,7 @@ class WindowStyleMask { ///The window can be resized by the user. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS ([Official API - NSWindow.StyleMask.miniaturizable](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644717-resizable)) + ///- macOS WKWebView ([Official API - NSWindow.StyleMask.miniaturizable](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644717-resizable)) static final RESIZABLE = WindowStyleMask._internalMultiPlatform(8, () { switch (defaultTargetPlatform) { case TargetPlatform.macOS: @@ -150,7 +150,7 @@ class WindowStyleMask { ///The window displays a title bar. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS ([Official API - NSWindow.StyleMask.titled](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644724-titled)) + ///- macOS WKWebView ([Official API - NSWindow.StyleMask.titled](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644724-titled)) static final TITLED = WindowStyleMask._internalMultiPlatform(1, () { switch (defaultTargetPlatform) { case TargetPlatform.macOS: @@ -164,7 +164,7 @@ class WindowStyleMask { ///The window is a panel. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS ([Official API - NSWindow.StyleMask.utilityWindow](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644672-utilitywindow)) + ///- macOS WKWebView ([Official API - NSWindow.StyleMask.utilityWindow](https://developer.apple.com/documentation/appkit/nswindow/stylemask/1644672-utilitywindow)) static final UTILITY_WINDOW = WindowStyleMask._internalMultiPlatform(16, () { switch (defaultTargetPlatform) { case TargetPlatform.macOS: @@ -216,26 +216,43 @@ class WindowStyleMask { return null; } + /// Gets a possible [WindowStyleMask] instance value with name [name]. + /// + /// Goes through [WindowStyleMask.values] looking for a value with + /// name [name], as reported by [WindowStyleMask.name]. + /// Returns the first value with the given name, otherwise `null`. + static WindowStyleMask? byName(String? name) { + if (name != null) { + try { + return WindowStyleMask.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [WindowStyleMask] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in WindowStyleMask.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; - ///Gets [int?] native value. + ///Gets [int] native value if supported by the current platform, otherwise `null`. int? toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - WindowStyleMask operator |(WindowStyleMask value) => - WindowStyleMask._internal( - value.toValue() | _value, - value.toNativeValue() != null && _nativeValue != null - ? value.toNativeValue()! | _nativeValue! - : _nativeValue); - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 0: return 'BORDERLESS'; @@ -262,4 +279,27 @@ class WindowStyleMask { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + WindowStyleMask operator |(WindowStyleMask value) => + WindowStyleMask._internal( + value.toValue() | _value, + value.toNativeValue() != null && _nativeValue != null + ? value.toNativeValue()! | _nativeValue! + : _nativeValue); + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/window_titlebar_separator_style.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/window_titlebar_separator_style.g.dart index 543e4e157..aceeb0712 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/window_titlebar_separator_style.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/window_titlebar_separator_style.g.dart @@ -19,7 +19,7 @@ class WindowTitlebarSeparatorStyle { ///A style indicating that the system determines the type of separator. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView static final AUTOMATIC = WindowTitlebarSeparatorStyle._internalMultiPlatform(0, () { switch (defaultTargetPlatform) { @@ -34,7 +34,7 @@ class WindowTitlebarSeparatorStyle { ///A style indicating that there’s no title bar separator. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView static final LINE = WindowTitlebarSeparatorStyle._internalMultiPlatform(2, () { switch (defaultTargetPlatform) { @@ -49,7 +49,7 @@ class WindowTitlebarSeparatorStyle { ///A style indicating that the title bar separator is a line. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView static final NONE = WindowTitlebarSeparatorStyle._internalMultiPlatform(1, () { switch (defaultTargetPlatform) { @@ -64,7 +64,7 @@ class WindowTitlebarSeparatorStyle { ///A style indicating that the title bar separator is a shadow. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS + ///- macOS WKWebView static final SHADOW = WindowTitlebarSeparatorStyle._internalMultiPlatform(3, () { switch (defaultTargetPlatform) { @@ -110,20 +110,45 @@ class WindowTitlebarSeparatorStyle { return null; } + /// Gets a possible [WindowTitlebarSeparatorStyle] instance value with name [name]. + /// + /// Goes through [WindowTitlebarSeparatorStyle.values] looking for a value with + /// name [name], as reported by [WindowTitlebarSeparatorStyle.name]. + /// Returns the first value with the given name, otherwise `null`. + static WindowTitlebarSeparatorStyle? byName(String? name) { + if (name != null) { + try { + return WindowTitlebarSeparatorStyle.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [WindowTitlebarSeparatorStyle] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => + { + for (final value in WindowTitlebarSeparatorStyle.values) + value.name(): value + }; + ///Gets [int] value. int toValue() => _value; - ///Gets [int?] native value. + ///Gets [int] native value if supported by the current platform, otherwise `null`. int? toNativeValue() => _nativeValue; - @override - int get hashCode => _value.hashCode; - - @override - bool operator ==(value) => value == _value; - - @override - String toString() { + ///Gets the name of the value. + String name() { switch (_value) { case 0: return 'AUTOMATIC'; @@ -136,4 +161,20 @@ class WindowTitlebarSeparatorStyle { } return _value.toString(); } + + @override + int get hashCode => _value.hashCode; + + @override + bool operator ==(value) => value == _value; + + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + + @override + String toString() { + return name(); + } } diff --git a/flutter_inappwebview_platform_interface/lib/src/types/window_type.g.dart b/flutter_inappwebview_platform_interface/lib/src/types/window_type.g.dart index 78d757c10..ea532135b 100644 --- a/flutter_inappwebview_platform_interface/lib/src/types/window_type.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/types/window_type.g.dart @@ -19,8 +19,8 @@ class WindowType { ///Adds the new browser window as a child window of the main window. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS - ///- Windows + ///- macOS WKWebView + ///- Windows WebView2 static final CHILD = WindowType._internalMultiPlatform('CHILD', () { switch (defaultTargetPlatform) { case TargetPlatform.macOS: @@ -36,7 +36,7 @@ class WindowType { ///Adds the new browser window as a new tab in a tabbed window of the main window. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS 10.12++ + ///- macOS WKWebView 10.12++ static final TABBED = WindowType._internalMultiPlatform('TABBED', () { switch (defaultTargetPlatform) { case TargetPlatform.macOS: @@ -50,8 +50,8 @@ class WindowType { ///Adds the new browser window as a separate new window from the main window. /// ///**Officially Supported Platforms/Implementations**: - ///- MacOS - ///- Windows + ///- macOS WKWebView + ///- Windows WebView2 static final WINDOW = WindowType._internalMultiPlatform('WINDOW', () { switch (defaultTargetPlatform) { case TargetPlatform.macOS: @@ -97,18 +97,65 @@ class WindowType { return null; } + /// Gets a possible [WindowType] instance value with name [name]. + /// + /// Goes through [WindowType.values] looking for a value with + /// name [name], as reported by [WindowType.name]. + /// Returns the first value with the given name, otherwise `null`. + static WindowType? byName(String? name) { + if (name != null) { + try { + return WindowType.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [WindowType] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in WindowType.values) value.name(): value + }; + ///Gets [String] value. String toValue() => _value; ///Gets [String] native value. String toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 'CHILD': + return 'CHILD'; + case 'TABBED': + return 'TABBED'; + case 'WINDOW': + return 'WINDOW'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return toNativeValue() != null; + } + @override String toString() { return _value; diff --git a/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/main.dart b/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/main.dart index fda76b888..5d91c1ee2 100644 --- a/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/main.dart +++ b/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/main.dart @@ -1,3 +1,5 @@ export 'platform_web_authenticate_session.dart'; export 'web_authenticate_session_settings.dart' - show WebAuthenticationSessionSettings; + show + WebAuthenticationSessionSettings, + WebAuthenticationSessionSettingsProperty; diff --git a/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/platform_web_authenticate_session.dart b/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/platform_web_authenticate_session.dart index 3bb6f3c17..71a240d4e 100755 --- a/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/platform_web_authenticate_session.dart +++ b/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/platform_web_authenticate_session.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import '../debug_logging_settings.dart'; import '../inappwebview_platform.dart'; @@ -8,17 +9,36 @@ import '../types/main.dart'; import '../web_uri.dart'; import 'web_authenticate_session_settings.dart'; +// ignore: uri_has_not_been_generated +part 'platform_web_authenticate_session.g.dart'; + ///A completion handler for the [PlatformWebAuthenticationSession]. typedef WebAuthenticationSessionCompletionHandler = Future Function( WebUri? url, WebAuthenticationSessionError? error)?; +///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSessionCreationParams} /// Object specifying creation parameters for creating a [PlatformWebAuthenticationSession]. /// /// Platform specific implementations can add additional fields by extending /// this class. +///{@endtemplate} +/// +///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSessionCreationParams.supported_platforms} +@SupportedPlatforms(platforms: [ + IOSPlatform(available: '11.0'), + MacOSPlatform(available: '10.15'), +]) +@immutable class PlatformWebAuthenticationSessionCreationParams { /// Used by the platform implementation to create a new [PlatformWebAuthenticationSession]. const PlatformWebAuthenticationSessionCreationParams(); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSessionCreationParams.isClassSupported} + ///Check if the current class is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isClassSupported({TargetPlatform? platform}) => + _PlatformWebAuthenticationSessionCreationParamsClassSupported + .isClassSupported(platform: platform); } ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession} @@ -31,21 +51,19 @@ class PlatformWebAuthenticationSessionCreationParams { ///Initialize the session with a URL that points to the authentication webpage. ///A browser loads and displays the page, from which the user can authenticate. ///In iOS, the browser is a secure, embedded web view. -///In macOS, the system opens the user’s default browser if it supports web authentication sessions, or Safari otherwise. +///In macOS, the system opens the user's default browser if it supports web authentication sessions, or Safari otherwise. /// ///On completion, the service sends a callback URL to the session with an authentication token, and the session passes this URL back to the app through a completion handler. -///[PlatformWebAuthenticationSession] ensures that only the calling app’s session receives the authentication callback, even when more than one app registers the same callback URL scheme. +///[PlatformWebAuthenticationSession] ensures that only the calling app's session receives the authentication callback, even when more than one app registers the same callback URL scheme. /// ///**NOTE**: Remember to dispose it when you don't need it anymore. -/// -///**NOTE for iOS**: Available only on iOS 11.0+. -/// -///**NOTE for MacOS**: Available only on MacOS 10.15+. -/// -///**Officially Supported Platforms/Implementations**: -///- iOS -///- MacOS ///{@endtemplate} +/// +///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.supported_platforms} +@SupportedPlatforms(platforms: [ + IOSPlatform(available: '11.0'), + MacOSPlatform(available: '10.15'), +]) abstract class PlatformWebAuthenticationSession extends PlatformInterface implements Disposable { ///Debug settings. @@ -100,24 +118,48 @@ abstract class PlatformWebAuthenticationSession extends PlatformInterface ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.id} ///ID used internally. ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.id.supported_platforms} + @SupportedPlatforms(platforms: [ + IOSPlatform(), + MacOSPlatform(), + ]) String get id => throw UnimplementedError('id is not implemented on the current platform'); ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.url} ///A URL with the `http` or `https` scheme pointing to the authentication webpage. ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.url.supported_platforms} + @SupportedPlatforms(platforms: [ + IOSPlatform(), + MacOSPlatform(), + ]) WebUri get url => throw UnimplementedError( 'url is not implemented on the current platform'); ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.callbackURLScheme} ///The custom URL scheme that the app expects in the callback URL. ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.callbackURLScheme.supported_platforms} + @SupportedPlatforms(platforms: [ + IOSPlatform(), + MacOSPlatform(), + ]) String? get callbackURLScheme => throw UnimplementedError( 'callbackURLScheme is not implemented on the current platform'); ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.initialSettings} ///Initial settings. ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.initialSettings.supported_platforms} + @SupportedPlatforms(platforms: [ + IOSPlatform(), + MacOSPlatform(), + ]) WebAuthenticationSessionSettings? get initialSettings => throw UnimplementedError( 'initialSettings is not implemented on the current platform'); @@ -125,6 +167,12 @@ abstract class PlatformWebAuthenticationSession extends PlatformInterface ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.onComplete} ///A completion handler the session calls when it completes successfully, or when the user cancels the session. ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.onComplete.supported_platforms} + @SupportedPlatforms(platforms: [ + IOSPlatform(), + MacOSPlatform(), + ]) WebAuthenticationSessionCompletionHandler get onComplete => throw UnimplementedError( 'onComplete is not implemented on the current platform'); @@ -140,6 +188,12 @@ abstract class PlatformWebAuthenticationSession extends PlatformInterface /// ///[initialSettings] represents initial settings. ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.create.supported_platforms} + @SupportedPlatforms(platforms: [ + IOSPlatform(), + MacOSPlatform(), + ]) Future create( {required WebUri url, String? callbackURLScheme, @@ -151,11 +205,19 @@ abstract class PlatformWebAuthenticationSession extends PlatformInterface ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.canStart} ///Indicates whether the session can begin. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - ASWebAuthenticationSession.canStart](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/3516277-canstart)) - ///- MacOS ([Official API - ASWebAuthenticationSession.canStart](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/3516277-canstart)) ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.canStart.supported_platforms} + @SupportedPlatforms(platforms: [ + IOSPlatform( + apiName: 'ASWebAuthenticationSession.canStart', + apiUrl: + 'https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/3516277-canstart'), + MacOSPlatform( + apiName: 'ASWebAuthenticationSession.canStart', + apiUrl: + 'https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/3516277-canstart'), + ]) Future canStart() { throw UnimplementedError( 'canStart is not implemented on the current platform'); @@ -168,11 +230,19 @@ abstract class PlatformWebAuthenticationSession extends PlatformInterface /// ///Only call this method once for a given [PlatformWebAuthenticationSession] instance after initialization. ///Calling the [start] method on a canceled session results in a failure. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - ASWebAuthenticationSession.start](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990953-start)) - ///- MacOS ([Official API - ASWebAuthenticationSession.start](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990953-start)) ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.start.supported_platforms} + @SupportedPlatforms(platforms: [ + IOSPlatform( + apiName: 'ASWebAuthenticationSession.start', + apiUrl: + 'https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990953-start'), + MacOSPlatform( + apiName: 'ASWebAuthenticationSession.start', + apiUrl: + 'https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990953-start'), + ]) Future start() { throw UnimplementedError( 'start is not implemented on the current platform'); @@ -183,11 +253,19 @@ abstract class PlatformWebAuthenticationSession extends PlatformInterface /// ///If the session has already presented a view with the authentication webpage, calling this method dismisses that view. ///Calling [cancel] on an already canceled session has no effect. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - ASWebAuthenticationSession.cancel](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990951-cancel)) - ///- MacOS ([Official API - ASWebAuthenticationSession.cancel](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990951-cancel)) ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.cancel.supported_platforms} + @SupportedPlatforms(platforms: [ + IOSPlatform( + apiName: 'ASWebAuthenticationSession.cancel', + apiUrl: + 'https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990951-cancel'), + MacOSPlatform( + apiName: 'ASWebAuthenticationSession.cancel', + apiUrl: + 'https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990951-cancel'), + ]) Future cancel() { throw UnimplementedError( 'cancel is not implemented on the current platform'); @@ -195,28 +273,54 @@ abstract class PlatformWebAuthenticationSession extends PlatformInterface ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.dispose} ///Disposes the web authentication session. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS - ///- MacOS ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.dispose.supported_platforms} + @SupportedPlatforms(platforms: [ + IOSPlatform(), + MacOSPlatform(), + ]) @override Future dispose() { throw UnimplementedError( - 'cancel is not implemented on the current platform'); + 'dispose is not implemented on the current platform'); } ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.isAvailable} ///Returns `true` if [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession) ///or [SFAuthenticationSession](https://developer.apple.com/documentation/safariservices/sfauthenticationsession) is available. ///Otherwise returns `false`. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS - ///- MacOS ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.isAvailable.supported_platforms} + @SupportedPlatforms(platforms: [ + IOSPlatform(), + MacOSPlatform(), + ]) Future isAvailable() { throw UnimplementedError( 'isAvailable is not implemented on the current platform'); } + + ///{@macro flutter_inappwebview_platform_interface.PlatformWebAuthenticationSessionCreationParams.isClassSupported} + bool isClassSupported({TargetPlatform? platform}) => + _PlatformWebAuthenticationSessionClassSupported.isClassSupported( + platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.isPropertySupported} + ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isPropertySupported(PlatformWebAuthenticationSessionProperty property, + {TargetPlatform? platform}) => + _PlatformWebAuthenticationSessionPropertySupported.isPropertySupported( + property, + platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.isMethodSupported} + ///Check if the given [method] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isMethodSupported(PlatformWebAuthenticationSessionMethod method, + {TargetPlatform? platform}) => + _PlatformWebAuthenticationSessionMethodSupported.isMethodSupported(method, + platform: platform); } diff --git a/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/platform_web_authenticate_session.g.dart b/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/platform_web_authenticate_session.g.dart new file mode 100644 index 000000000..d631f1b92 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/platform_web_authenticate_session.g.dart @@ -0,0 +1,252 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'platform_web_authenticate_session.dart'; + +// ************************************************************************** +// SupportedPlatformsGenerator +// ************************************************************************** + +extension _PlatformWebAuthenticationSessionCreationParamsClassSupported + on PlatformWebAuthenticationSessionCreationParams { + ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSessionCreationParams.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView 11.0+ + ///- macOS WKWebView 10.15+ + /// + ///Use the [PlatformWebAuthenticationSessionCreationParams.isClassSupported] method to check if this class is supported at runtime. + ///{@endtemplate} + static bool isClassSupported({TargetPlatform? platform}) { + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + } +} + +extension _PlatformWebAuthenticationSessionClassSupported + on PlatformWebAuthenticationSession { + ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView 11.0+ + ///- macOS WKWebView 10.15+ + /// + ///Use the [PlatformWebAuthenticationSession.isClassSupported] method to check if this class is supported at runtime. + ///{@endtemplate} + static bool isClassSupported({TargetPlatform? platform}) { + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + } +} + +///List of [PlatformWebAuthenticationSession]'s properties that can be used to check i they are supported or not by the current platform. +enum PlatformWebAuthenticationSessionProperty { + ///Can be used to check if the [PlatformWebAuthenticationSession.callbackURLScheme] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.callbackURLScheme.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///Use the [PlatformWebAuthenticationSession.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + callbackURLScheme, + + ///Can be used to check if the [PlatformWebAuthenticationSession.id] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.id.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///Use the [PlatformWebAuthenticationSession.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + id, + + ///Can be used to check if the [PlatformWebAuthenticationSession.initialSettings] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.initialSettings.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///Use the [PlatformWebAuthenticationSession.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + initialSettings, + + ///Can be used to check if the [PlatformWebAuthenticationSession.onComplete] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.onComplete.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [url]: all platforms + ///- [error]: all platforms + /// + ///Use the [PlatformWebAuthenticationSession.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + onComplete, + + ///Can be used to check if the [PlatformWebAuthenticationSession.url] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.url.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///Use the [PlatformWebAuthenticationSession.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + url, +} + +extension _PlatformWebAuthenticationSessionPropertySupported + on PlatformWebAuthenticationSession { + static bool isPropertySupported( + PlatformWebAuthenticationSessionProperty property, + {TargetPlatform? platform}) { + switch (property) { + case PlatformWebAuthenticationSessionProperty.callbackURLScheme: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebAuthenticationSessionProperty.id: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebAuthenticationSessionProperty.initialSettings: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebAuthenticationSessionProperty.onComplete: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebAuthenticationSessionProperty.url: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + } + } +} + +///List of [PlatformWebAuthenticationSession]'s methods that can be used to check if they are supported or not by the current platform. +enum PlatformWebAuthenticationSessionMethod { + ///Can be used to check if the [PlatformWebAuthenticationSession.canStart] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.canStart.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView ([Official API - ASWebAuthenticationSession.canStart](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/3516277-canstart)) + ///- macOS WKWebView ([Official API - ASWebAuthenticationSession.canStart](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/3516277-canstart)) + /// + ///Use the [PlatformWebAuthenticationSession.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + canStart, + + ///Can be used to check if the [PlatformWebAuthenticationSession.cancel] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.cancel.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView ([Official API - ASWebAuthenticationSession.cancel](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990951-cancel)) + ///- macOS WKWebView ([Official API - ASWebAuthenticationSession.cancel](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990951-cancel)) + /// + ///Use the [PlatformWebAuthenticationSession.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + cancel, + + ///Can be used to check if the [PlatformWebAuthenticationSession.create] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.create.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [url]: all platforms + ///- [callbackURLScheme]: all platforms + ///- [onComplete]: all platforms + ///- [initialSettings]: all platforms + /// + ///Use the [PlatformWebAuthenticationSession.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + create, + + ///Can be used to check if the [PlatformWebAuthenticationSession.dispose] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.dispose.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///Use the [PlatformWebAuthenticationSession.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + dispose, + + ///Can be used to check if the [PlatformWebAuthenticationSession.isAvailable] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.isAvailable.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///Use the [PlatformWebAuthenticationSession.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + isAvailable, + + ///Can be used to check if the [PlatformWebAuthenticationSession.start] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebAuthenticationSession.start.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView ([Official API - ASWebAuthenticationSession.start](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990953-start)) + ///- macOS WKWebView ([Official API - ASWebAuthenticationSession.start](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/2990953-start)) + /// + ///Use the [PlatformWebAuthenticationSession.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + start, +} + +extension _PlatformWebAuthenticationSessionMethodSupported + on PlatformWebAuthenticationSession { + static bool isMethodSupported(PlatformWebAuthenticationSessionMethod method, + {TargetPlatform? platform}) { + switch (method) { + case PlatformWebAuthenticationSessionMethod.canStart: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebAuthenticationSessionMethod.cancel: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebAuthenticationSessionMethod.create: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebAuthenticationSessionMethod.dispose: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebAuthenticationSessionMethod.isAvailable: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebAuthenticationSessionMethod.start: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + } + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/web_authenticate_session_settings.dart b/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/web_authenticate_session_settings.dart index 7ce0505ff..037f3b4c0 100755 --- a/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/web_authenticate_session_settings.dart +++ b/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/web_authenticate_session_settings.dart @@ -1,10 +1,17 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + import 'platform_web_authenticate_session.dart'; +import '../types/enum_method.dart'; part 'web_authenticate_session_settings.g.dart'; ///Class that represents the settings that can be used for a [PlatformWebAuthenticationSession]. @ExchangeableObject(copyMethod: true) +@SupportedPlatforms(platforms: [ + IOSPlatform(available: '13.0'), + MacOSPlatform(available: '10.15'), +]) class WebAuthenticationSessionSettings_ { ///A Boolean value that indicates whether the session should ask the browser for a private authentication session. /// @@ -16,22 +23,20 @@ class WebAuthenticationSessionSettings_ { ///The value of this property is `false` by default. /// ///Set this property before you call [PlatformWebAuthenticationSession.start]. Otherwise it has no effect. - /// - ///**NOTE for iOS**: Available only on iOS 13.0+. - /// - ///**NOTE for MacOS**: Available only on iOS 10.15+. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS - ///- MacOS + @SupportedPlatforms(platforms: [ + IOSPlatform(available: '13.0'), + MacOSPlatform(available: '10.15'), + ]) bool? prefersEphemeralWebBrowserSession; WebAuthenticationSessionSettings_( {this.prefersEphemeralWebBrowserSession = false}); - Map toMap() { - return { - "prefersEphemeralWebBrowserSession": prefersEphemeralWebBrowserSession - }; - } + ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. + static bool isPropertySupported( + WebAuthenticationSessionSettingsProperty property, + {TargetPlatform? platform}) => + _WebAuthenticationSessionSettingsPropertySupported.isPropertySupported( + property, + platform: platform); } diff --git a/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/web_authenticate_session_settings.g.dart b/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/web_authenticate_session_settings.g.dart index e94d4745b..24ac29ac2 100644 --- a/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/web_authenticate_session_settings.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/web_authentication_session/web_authenticate_session_settings.g.dart @@ -7,6 +7,10 @@ part of 'web_authenticate_session_settings.dart'; // ************************************************************************** ///Class that represents the settings that can be used for a [PlatformWebAuthenticationSession]. +/// +///**Officially Supported Platforms/Implementations**: +///- iOS WKWebView 13.0+ +///- macOS WKWebView 10.15+ class WebAuthenticationSessionSettings { ///A Boolean value that indicates whether the session should ask the browser for a private authentication session. /// @@ -19,19 +23,21 @@ class WebAuthenticationSessionSettings { /// ///Set this property before you call [PlatformWebAuthenticationSession.start]. Otherwise it has no effect. /// - ///**NOTE for iOS**: Available only on iOS 13.0+. - /// - ///**NOTE for MacOS**: Available only on iOS 10.15+. - /// ///**Officially Supported Platforms/Implementations**: - ///- iOS - ///- MacOS + ///- iOS WKWebView 13.0+ + ///- macOS WKWebView 10.15+ bool? prefersEphemeralWebBrowserSession; + + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView 13.0+ + ///- macOS WKWebView 10.15+ WebAuthenticationSessionSettings( {this.prefersEphemeralWebBrowserSession = false}); ///Gets a possible [WebAuthenticationSessionSettings] instance from a [Map] value. - static WebAuthenticationSessionSettings? fromMap(Map? map) { + static WebAuthenticationSessionSettings? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -41,9 +47,18 @@ class WebAuthenticationSessionSettings { return instance; } - Map toMap() { + ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. + static bool isPropertySupported( + WebAuthenticationSessionSettingsProperty property, + {TargetPlatform? platform}) => + _WebAuthenticationSessionSettingsPropertySupported.isPropertySupported( + property, + platform: platform); + + ///Converts instance to a map. + Map toMap({EnumMethod? enumMethod}) { return { - "prefersEphemeralWebBrowserSession": prefersEphemeralWebBrowserSession + "prefersEphemeralWebBrowserSession": prefersEphemeralWebBrowserSession, }; } @@ -63,3 +78,37 @@ class WebAuthenticationSessionSettings { return 'WebAuthenticationSessionSettings{prefersEphemeralWebBrowserSession: $prefersEphemeralWebBrowserSession}'; } } + +// ************************************************************************** +// SupportedPlatformsGenerator +// ************************************************************************** + +///List of [WebAuthenticationSessionSettings]'s properties that can be used to check i they are supported or not by the current platform. +enum WebAuthenticationSessionSettingsProperty { + ///Can be used to check if the [WebAuthenticationSessionSettings.prefersEphemeralWebBrowserSession] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.WebAuthenticationSessionSettings.prefersEphemeralWebBrowserSession.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView 13.0+ + ///- macOS WKWebView 10.15+ + /// + ///Use the [WebAuthenticationSessionSettings.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + prefersEphemeralWebBrowserSession, +} + +extension _WebAuthenticationSessionSettingsPropertySupported + on WebAuthenticationSessionSettings { + static bool isPropertySupported( + WebAuthenticationSessionSettingsProperty property, + {TargetPlatform? platform}) { + switch (property) { + case WebAuthenticationSessionSettingsProperty + .prefersEphemeralWebBrowserSession: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + } + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/web_message/platform_web_message_channel.dart b/flutter_inappwebview_platform_interface/lib/src/web_message/platform_web_message_channel.dart index 75767a3b7..c8c66af13 100644 --- a/flutter_inappwebview_platform_interface/lib/src/web_message/platform_web_message_channel.dart +++ b/flutter_inappwebview_platform_interface/lib/src/web_message/platform_web_message_channel.dart @@ -1,28 +1,84 @@ import 'package:flutter/foundation.dart'; +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import 'package:flutter_inappwebview_platform_interface/src/types/disposable.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import '../inappwebview_platform.dart'; import 'platform_web_message_port.dart'; +// ignore: uri_has_not_been_generated +part 'platform_web_message_channel.g.dart'; + +///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams} /// Object specifying creation parameters for creating a [PlatformWebMessageChannel]. /// /// Platform specific implementations can add additional fields by extending /// this class. +///{@endtemplate} +/// +///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.supported_platforms} +@SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), +]) @immutable class PlatformWebMessageChannelCreationParams { /// Used by the platform implementation to create a new [PlatformWebMessageChannel]. const PlatformWebMessageChannelCreationParams( {required this.id, required this.port1, required this.port2}); - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel.id} + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.id} + ///Message Channel ID used internally. + ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.id.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + ]) final String id; - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel.port1} + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.port1} + ///The first [PlatformWebMessagePort] object of the channel. + ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.port1.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + ]) final PlatformWebMessagePort port1; - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel.port2} + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.port2} + ///The second [PlatformWebMessagePort] object of the channel. + ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.port2.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + ]) final PlatformWebMessagePort port2; + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.isClassSupported} + ///Check if the current class is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isClassSupported({TargetPlatform? platform}) => + _PlatformWebMessageChannelCreationParamsClassSupported.isClassSupported( + platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.isPropertySupported} + ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isPropertySupported( + PlatformWebMessageChannelCreationParamsProperty property, + {TargetPlatform? platform}) => + _PlatformWebMessageChannelCreationParamsPropertySupported + .isPropertySupported(property, platform: platform); + @override String toString() { return 'PlatformWebMessageChannelCreationParams{id: $id, port1: $port1, port2: $port2}'; @@ -31,12 +87,14 @@ class PlatformWebMessageChannelCreationParams { ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannel} ///The representation of the [HTML5 message channels](https://html.spec.whatwg.org/multipage/web-messaging.html#message-channels). -/// -///**Officially Supported Platforms/Implementations**: -///- Android native WebView -///- iOS -///- MacOS ///{@endtemplate} +/// +///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel.supported_platforms} +@SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), +]) abstract class PlatformWebMessageChannel extends PlatformInterface implements Disposable { /// Creates a new [PlatformWebMessageChannel] @@ -82,19 +140,19 @@ abstract class PlatformWebMessageChannel extends PlatformInterface /// The parameters used to initialize the [PlatformWebMessageChannel]. final PlatformWebMessageChannelCreationParams params; - ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannel.id} - ///Message Channel ID used internally. - ///{@endtemplate} + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.id} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.id.supported_platforms} String get id => params.id; - ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannel.port1} - ///The first [PlatformWebMessagePort] object of the channel. - ///{@endtemplate} + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.port1} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.port1.supported_platforms} PlatformWebMessagePort get port1 => params.port1; - ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannel.port2} - ///The second [PlatformWebMessagePort] object of the channel. - ///{@endtemplate} + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.port2} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.port2.supported_platforms} PlatformWebMessagePort get port2 => params.port2; PlatformWebMessageChannel? fromMap(Map? map) { @@ -102,15 +160,43 @@ abstract class PlatformWebMessageChannel extends PlatformInterface 'fromMap is not implemented on the current platform'); } - ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannel} + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannel.dispose} ///Disposes the web message channel. ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel.dispose.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + ]) @override void dispose() { throw UnimplementedError( 'dispose is not implemented on the current platform'); } + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.isClassSupported} + bool isClassSupported({TargetPlatform? platform}) => + _PlatformWebMessageChannelClassSupported.isClassSupported( + platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannel.isPropertySupported} + ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isPropertySupported( + PlatformWebMessageChannelCreationParamsProperty property, + {TargetPlatform? platform}) => + params.isPropertySupported(property, platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannel.isMethodSupported} + ///Check if the given [method] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isMethodSupported(PlatformWebMessageChannelMethod method, + {TargetPlatform? platform}) => + _PlatformWebMessageChannelMethodSupported.isMethodSupported(method, + platform: platform); + @override String toString() { return 'PlatformWebMessageChannel{id: $id, port1: $port1, port2: $port2}'; diff --git a/flutter_inappwebview_platform_interface/lib/src/web_message/platform_web_message_channel.g.dart b/flutter_inappwebview_platform_interface/lib/src/web_message/platform_web_message_channel.g.dart new file mode 100644 index 000000000..3fa50511c --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/web_message/platform_web_message_channel.g.dart @@ -0,0 +1,136 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'platform_web_message_channel.dart'; + +// ************************************************************************** +// SupportedPlatformsGenerator +// ************************************************************************** + +extension _PlatformWebMessageChannelCreationParamsClassSupported + on PlatformWebMessageChannelCreationParams { + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///Use the [PlatformWebMessageChannelCreationParams.isClassSupported] method to check if this class is supported at runtime. + ///{@endtemplate} + static bool isClassSupported({TargetPlatform? platform}) { + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.android, TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + } +} + +///List of [PlatformWebMessageChannelCreationParams]'s properties that can be used to check i they are supported or not by the current platform. +enum PlatformWebMessageChannelCreationParamsProperty { + ///Can be used to check if the [PlatformWebMessageChannelCreationParams.id] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.id.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///Use the [PlatformWebMessageChannelCreationParams.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + id, + + ///Can be used to check if the [PlatformWebMessageChannelCreationParams.port1] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.port1.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///Use the [PlatformWebMessageChannelCreationParams.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + port1, + + ///Can be used to check if the [PlatformWebMessageChannelCreationParams.port2] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannelCreationParams.port2.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///Use the [PlatformWebMessageChannelCreationParams.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + port2, +} + +extension _PlatformWebMessageChannelCreationParamsPropertySupported + on PlatformWebMessageChannelCreationParams { + static bool isPropertySupported( + PlatformWebMessageChannelCreationParamsProperty property, + {TargetPlatform? platform}) { + switch (property) { + case PlatformWebMessageChannelCreationParamsProperty.id: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.android, TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebMessageChannelCreationParamsProperty.port1: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.android, TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebMessageChannelCreationParamsProperty.port2: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.android, TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + } + } +} + +extension _PlatformWebMessageChannelClassSupported + on PlatformWebMessageChannel { + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannel.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///Use the [PlatformWebMessageChannel.isClassSupported] method to check if this class is supported at runtime. + ///{@endtemplate} + static bool isClassSupported({TargetPlatform? platform}) { + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.android, TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + } +} + +///List of [PlatformWebMessageChannel]'s methods that can be used to check if they are supported or not by the current platform. +enum PlatformWebMessageChannelMethod { + ///Can be used to check if the [PlatformWebMessageChannel.dispose] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageChannel.dispose.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///Use the [PlatformWebMessageChannel.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + dispose, +} + +extension _PlatformWebMessageChannelMethodSupported + on PlatformWebMessageChannel { + static bool isMethodSupported(PlatformWebMessageChannelMethod method, + {TargetPlatform? platform}) { + switch (method) { + case PlatformWebMessageChannelMethod.dispose: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.android, TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + } + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/web_message/platform_web_message_listener.dart b/flutter_inappwebview_platform_interface/lib/src/web_message/platform_web_message_listener.dart index 5cca28c6e..bf6f31143 100644 --- a/flutter_inappwebview_platform_interface/lib/src/web_message/platform_web_message_listener.dart +++ b/flutter_inappwebview_platform_interface/lib/src/web_message/platform_web_message_listener.dart @@ -1,4 +1,5 @@ import 'package:flutter/foundation.dart'; +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import 'package:flutter_inappwebview_platform_interface/src/types/disposable.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import '../in_app_webview/platform_inappwebview_controller.dart'; @@ -6,10 +7,22 @@ import '../inappwebview_platform.dart'; import '../types/main.dart'; import 'web_message.dart'; +// ignore: uri_has_not_been_generated +part 'platform_web_message_listener.g.dart'; + +///{@template flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams} /// Object specifying creation parameters for creating a [PlatformWebMessageListener]. /// /// Platform specific implementations can add additional fields by extending /// this class. +///{@endtemplate} +/// +///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.supported_platforms} +@SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), +]) @immutable class PlatformWebMessageListenerCreationParams { /// Used by the platform implementation to create a new [PlatformWebMessageListener]. @@ -18,15 +31,68 @@ class PlatformWebMessageListenerCreationParams { this.allowedOriginRules, this.onPostMessage}); - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener.jsObjectName} + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.jsObjectName} + ///The name for the injected JavaScript object. + ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.jsObjectName.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + ]) final String jsObjectName; - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener.allowedOriginRules} + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.allowedOriginRules} + ///A set of matching rules for the allowed origins. + ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.allowedOriginRules.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + ]) final Set? allowedOriginRules; - ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener.onPostMessage} + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.onPostMessage} + ///Event that receives a message sent by a `postMessage()` on the injected JavaScript object. + /// + ///Note that when the frame is `file:` or `content:` origin, the value of [sourceOrigin] is `null`. + /// + ///- [message] represents the message from JavaScript. + ///- [sourceOrigin] represents the origin of the frame that the message is from. + ///- [isMainFrame] is `true` if the message is from the main frame. + ///- [replyProxy] is used to reply back to the JavaScript object. + ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.onPostMessage.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform( + apiName: 'WebViewCompat.WebMessageListener.onPostMessage', + apiUrl: + 'https://developer.android.com/reference/androidx/webkit/WebViewCompat.WebMessageListener#onPostMessage(android.webkit.WebView,%20androidx.webkit.WebMessageCompat,%20android.net.Uri,%20boolean,%20androidx.webkit.JavaScriptReplyProxy)'), + IOSPlatform(), + MacOSPlatform(), + ]) final OnPostMessageCallback? onPostMessage; + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.isClassSupported} + ///Check if the current class is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isClassSupported({TargetPlatform? platform}) => + _PlatformWebMessageListenerCreationParamsClassSupported.isClassSupported( + platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.isPropertySupported} + ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isPropertySupported( + PlatformWebMessageListenerCreationParamsProperty property, + {TargetPlatform? platform}) => + _PlatformWebMessageListenerCreationParamsPropertySupported + .isPropertySupported(property, platform: platform); + @override String toString() { return 'PlatformWebMessageListenerCreationParams{jsObjectName: $jsObjectName, allowedOriginRules: $allowedOriginRules, onPostMessage: $onPostMessage}'; @@ -35,12 +101,14 @@ class PlatformWebMessageListenerCreationParams { ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageListener} ///This listener receives messages sent on the JavaScript object which was injected by [PlatformInAppWebViewController.addWebMessageListener]. -/// -///**Officially Supported Platforms/Implementations**: -///- Android native WebView -///- iOS -///- MacOS ///{@endtemplate} +/// +///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener.supported_platforms} +@SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), +]) abstract class PlatformWebMessageListener extends PlatformInterface implements Disposable { /// Creates a new [PlatformWebMessageListener] @@ -59,6 +127,21 @@ abstract class PlatformWebMessageListener extends PlatformInterface return webMessageListener; } + /// Creates a new [PlatformWebMessageListener] to access static methods. + factory PlatformWebMessageListener.static() { + assert( + InAppWebViewPlatform.instance != null, + 'A platform implementation for `flutter_inappwebview` has not been set. Please ' + 'ensure that an implementation of `InAppWebViewPlatform` has been set to ' + '`InAppWebViewPlatform.instance` before use. For unit testing, ' + '`InAppWebViewPlatform.instance` can be set with your own test implementation.', + ); + final PlatformWebMessageListener webMessageListenerStatic = + InAppWebViewPlatform.instance!.createPlatformWebMessageListenerStatic(); + PlatformInterface.verify(webMessageListenerStatic, _token); + return webMessageListenerStatic; + } + /// Used by the platform implementation to create a new [PlatformWebMessageListener]. /// /// Should only be used by platform implementations because they can't extend @@ -71,28 +154,19 @@ abstract class PlatformWebMessageListener extends PlatformInterface /// The parameters used to initialize the [PlatformWebMessageListener]. final PlatformWebMessageListenerCreationParams params; - ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageListener.jsObjectName} - ///The name for the injected JavaScript object. - ///{@endtemplate} + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.jsObjectName} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.jsObjectName.supported_platforms} String get jsObjectName => params.jsObjectName; - ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageListener.allowedOriginRules} - ///A set of matching rules for the allowed origins. - ///{@endtemplate} + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.allowedOriginRules} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.allowedOriginRules.supported_platforms} Set? get allowedOriginRules => params.allowedOriginRules; - ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageListener.onPostMessage} - ///Event that receives a message sent by a `postMessage()` on the injected JavaScript object. + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.onPostMessage} /// - ///Note that when the frame is `file:` or `content:` origin, the value of [sourceOrigin] is `null`. - /// - ///- [message] represents the message from JavaScript. - ///- [sourceOrigin] represents the origin of the frame that the message is from. - ///- [isMainFrame] is `true` if the message is from the main frame. - ///- [replyProxy] is used to reply back to the JavaScript object. - /// - ///**Official Android API**: https://developer.android.com/reference/androidx/webkit/WebViewCompat.WebMessageListener#onPostMessage(android.webkit.WebView,%20androidx.webkit.WebMessageCompat,%20android.net.Uri,%20boolean,%20androidx.webkit.JavaScriptReplyProxy) - ///{@endtemplate} + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.onPostMessage.supported_platforms} OnPostMessageCallback? get onPostMessage => params.onPostMessage; Map toMap() { @@ -108,12 +182,40 @@ abstract class PlatformWebMessageListener extends PlatformInterface ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageListener.dispose} ///Disposes the channel. ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener.dispose.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + ]) @override void dispose() { throw UnimplementedError( 'dispose is not implemented on the current platform.'); } + ///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.isClassSupported} + bool isClassSupported({TargetPlatform? platform}) => + _PlatformWebMessageListenerClassSupported.isClassSupported( + platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageListener.isPropertySupported} + ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isPropertySupported( + PlatformWebMessageListenerCreationParamsProperty property, + {TargetPlatform? platform}) => + params.isPropertySupported(property, platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageListener.isMethodSupported} + ///Check if the given [method] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isMethodSupported(PlatformWebMessageListenerMethod method, + {TargetPlatform? platform}) => + _PlatformWebMessageListenerMethodSupported.isMethodSupported(method, + platform: platform); + @override String toString() { return 'PlatformWebMessageListener{jsObjectName: $jsObjectName, allowedOriginRules: $allowedOriginRules, onPostMessage: $onPostMessage}'; diff --git a/flutter_inappwebview_platform_interface/lib/src/web_message/platform_web_message_listener.g.dart b/flutter_inappwebview_platform_interface/lib/src/web_message/platform_web_message_listener.g.dart new file mode 100644 index 000000000..5f0da9a32 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/web_message/platform_web_message_listener.g.dart @@ -0,0 +1,142 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'platform_web_message_listener.dart'; + +// ************************************************************************** +// SupportedPlatformsGenerator +// ************************************************************************** + +extension _PlatformWebMessageListenerCreationParamsClassSupported + on PlatformWebMessageListenerCreationParams { + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///Use the [PlatformWebMessageListenerCreationParams.isClassSupported] method to check if this class is supported at runtime. + ///{@endtemplate} + static bool isClassSupported({TargetPlatform? platform}) { + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.android, TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + } +} + +///List of [PlatformWebMessageListenerCreationParams]'s properties that can be used to check i they are supported or not by the current platform. +enum PlatformWebMessageListenerCreationParamsProperty { + ///Can be used to check if the [PlatformWebMessageListenerCreationParams.allowedOriginRules] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.allowedOriginRules.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///Use the [PlatformWebMessageListenerCreationParams.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + allowedOriginRules, + + ///Can be used to check if the [PlatformWebMessageListenerCreationParams.jsObjectName] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.jsObjectName.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///Use the [PlatformWebMessageListenerCreationParams.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + jsObjectName, + + ///Can be used to check if the [PlatformWebMessageListenerCreationParams.onPostMessage] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageListenerCreationParams.onPostMessage.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView ([Official API - WebViewCompat.WebMessageListener.onPostMessage](https://developer.android.com/reference/androidx/webkit/WebViewCompat.WebMessageListener#onPostMessage(android.webkit.WebView,%20androidx.webkit.WebMessageCompat,%20android.net.Uri,%20boolean,%20androidx.webkit.JavaScriptReplyProxy))) + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [message]: all platforms + ///- [sourceOrigin]: all platforms + ///- [isMainFrame]: all platforms + ///- [replyProxy]: all platforms + /// + ///Use the [PlatformWebMessageListenerCreationParams.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + onPostMessage, +} + +extension _PlatformWebMessageListenerCreationParamsPropertySupported + on PlatformWebMessageListenerCreationParams { + static bool isPropertySupported( + PlatformWebMessageListenerCreationParamsProperty property, + {TargetPlatform? platform}) { + switch (property) { + case PlatformWebMessageListenerCreationParamsProperty.allowedOriginRules: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.android, TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebMessageListenerCreationParamsProperty.jsObjectName: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.android, TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebMessageListenerCreationParamsProperty.onPostMessage: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.android, TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + } + } +} + +extension _PlatformWebMessageListenerClassSupported + on PlatformWebMessageListener { + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageListener.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///Use the [PlatformWebMessageListener.isClassSupported] method to check if this class is supported at runtime. + ///{@endtemplate} + static bool isClassSupported({TargetPlatform? platform}) { + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.android, TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + } +} + +///List of [PlatformWebMessageListener]'s methods that can be used to check if they are supported or not by the current platform. +enum PlatformWebMessageListenerMethod { + ///Can be used to check if the [PlatformWebMessageListener.dispose] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebMessageListener.dispose.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + /// + ///Use the [PlatformWebMessageListener.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + dispose, +} + +extension _PlatformWebMessageListenerMethodSupported + on PlatformWebMessageListener { + static bool isMethodSupported(PlatformWebMessageListenerMethod method, + {TargetPlatform? platform}) { + switch (method) { + case PlatformWebMessageListenerMethod.dispose: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.android, TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + } + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/web_message/platform_web_message_port.dart b/flutter_inappwebview_platform_interface/lib/src/web_message/platform_web_message_port.dart index 7265aa320..35210403e 100644 --- a/flutter_inappwebview_platform_interface/lib/src/web_message/platform_web_message_port.dart +++ b/flutter_inappwebview_platform_interface/lib/src/web_message/platform_web_message_port.dart @@ -2,6 +2,7 @@ import 'package:flutter/foundation.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import '../inappwebview_platform.dart'; +import '../types/enum_method.dart'; import '../types/web_message_callback.dart'; import 'web_message.dart'; @@ -103,7 +104,7 @@ abstract class IWebMessagePort { 'close is not implemented on the current platform'); } - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { throw UnimplementedError( 'toMap is not implemented on the current platform'); } diff --git a/flutter_inappwebview_platform_interface/lib/src/web_message/web_message.dart b/flutter_inappwebview_platform_interface/lib/src/web_message/web_message.dart index 33476b95c..df817e7e4 100644 --- a/flutter_inappwebview_platform_interface/lib/src/web_message/web_message.dart +++ b/flutter_inappwebview_platform_interface/lib/src/web_message/web_message.dart @@ -3,6 +3,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_i import '../platform_webview_feature.dart'; import 'platform_web_message_port.dart'; +import '../types/enum_method.dart'; part 'web_message.g.dart'; diff --git a/flutter_inappwebview_platform_interface/lib/src/web_message/web_message.g.dart b/flutter_inappwebview_platform_interface/lib/src/web_message/web_message.g.dart index facac8e4c..affc1cda3 100644 --- a/flutter_inappwebview_platform_interface/lib/src/web_message/web_message.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/web_message/web_message.g.dart @@ -56,27 +56,66 @@ class WebMessageType { return null; } + /// Gets a possible [WebMessageType] instance value with name [name]. + /// + /// Goes through [WebMessageType.values] looking for a value with + /// name [name], as reported by [WebMessageType.name]. + /// Returns the first value with the given name, otherwise `null`. + static WebMessageType? byName(String? name) { + if (name != null) { + try { + return WebMessageType.values + .firstWhere((element) => element.name() == name); + } catch (e) { + return null; + } + } + return null; + } + + /// Creates a map from the names of [WebMessageType] values to the values. + /// + /// The collection that this method is called on is expected to have + /// values with distinct names, like the `values` list of an enum class. + /// Only one value for each name can occur in the created map, + /// so if two or more values have the same name (either being the + /// same value, or being values of different enum type), at most one of + /// them will be represented in the returned map. + static Map asNameMap() => { + for (final value in WebMessageType.values) value.name(): value + }; + ///Gets [int] value. int toValue() => _value; ///Gets [int] native value. int toNativeValue() => _nativeValue; + ///Gets the name of the value. + String name() { + switch (_value) { + case 1: + return 'ARRAY_BUFFER'; + case 0: + return 'STRING'; + } + return _value.toString(); + } + @override int get hashCode => _value.hashCode; @override bool operator ==(value) => value == _value; + ///Checks if the value is supported by the [defaultTargetPlatform]. + bool isSupported() { + return true; + } + @override String toString() { - switch (_value) { - case 1: - return 'ARRAY_BUFFER'; - case 0: - return 'STRING'; - } - return _value.toString(); + return name(); } } @@ -104,7 +143,8 @@ class WebMessage { } ///Gets a possible [WebMessage] instance from a [Map] value. - static WebMessage? fromMap(Map? map) { + static WebMessage? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -113,17 +153,25 @@ class WebMessage { ports: map['ports'] != null ? List.from(map['ports'].map((e) => e)) : null, - type: WebMessageType.fromNativeValue(map['type'])!, + type: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => WebMessageType.fromNativeValue(map['type']), + EnumMethod.value => WebMessageType.fromValue(map['type']), + EnumMethod.name => WebMessageType.byName(map['type']) + }!, ); return instance; } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "data": data, - "ports": ports?.map((e) => e.toMap()).toList(), - "type": type.toNativeValue(), + "ports": ports?.map((e) => e.toMap(enumMethod: enumMethod)).toList(), + "type": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => type.toNativeValue(), + EnumMethod.value => type.toValue(), + EnumMethod.name => type.name() + }, }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/web_storage/platform_web_storage.dart b/flutter_inappwebview_platform_interface/lib/src/web_storage/platform_web_storage.dart index dcd40e254..067e80f46 100644 --- a/flutter_inappwebview_platform_interface/lib/src/web_storage/platform_web_storage.dart +++ b/flutter_inappwebview_platform_interface/lib/src/web_storage/platform_web_storage.dart @@ -1,4 +1,5 @@ import 'package:flutter/foundation.dart'; +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import 'package:flutter_inappwebview_platform_interface/src/types/disposable.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; @@ -7,10 +8,27 @@ import '../inappwebview_platform.dart'; import '../types/main.dart'; import 'web_storage_item.dart'; +part 'platform_web_storage.g.dart'; + +/// Object specifying creation parameters for creating a [PlatformWebStorage]. +/// +/// Platform specific implementations can add additional fields by extending +/// this class. +///{@template flutter_inappwebview_platform_interface.PlatformWebStorageCreationParams} /// Object specifying creation parameters for creating a [PlatformWebStorage]. /// /// Platform specific implementations can add additional fields by extending /// this class. +///{@endtemplate} +/// +///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageCreationParams.supported_platforms} +@SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() +]) @immutable class PlatformWebStorageCreationParams { /// Used by the platform implementation to create a new [PlatformWebStorage]. @@ -18,23 +36,58 @@ class PlatformWebStorageCreationParams { {required this.localStorage, required this.sessionStorage}); ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage.localStorage} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage.localStorage.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) final PlatformLocalStorage localStorage; ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage.sessionStorage} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage.sessionStorage.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) final PlatformSessionStorage sessionStorage; + + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageCreationParams.isClassSupported} + ///Check if the current class is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isClassSupported({TargetPlatform? platform}) => + _PlatformWebStorageCreationParamsClassSupported.isClassSupported( + platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageCreationParams.isPropertySupported} + ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isPropertySupported(PlatformWebStorageCreationParamsProperty property, + {TargetPlatform? platform}) => + _PlatformWebStorageCreationParamsPropertySupported.isPropertySupported( + property, + platform: platform); } ///{@template flutter_inappwebview_platform_interface.PlatformWebStorage} ///Class that provides access to the JavaScript [Web Storage API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API): `window.sessionStorage` and `window.localStorage`. ///It used by [PlatformInAppWebViewController.webStorage]. -/// -///**Officially Supported Platforms/Implementations**: -///- Android native WebView -///- iOS -///- MacOS -///- Web -///- Windows ///{@endtemplate} +///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage.supported_platforms} +@SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() +]) abstract class PlatformWebStorage extends PlatformInterface implements Disposable { /// Creates a new [PlatformWebStorage] @@ -52,6 +105,21 @@ abstract class PlatformWebStorage extends PlatformInterface return webStorage; } + /// Creates a new empty [PlatformWebStorage] to access static methods. + factory PlatformWebStorage.static() { + assert( + InAppWebViewPlatform.instance != null, + 'A platform implementation for `flutter_inappwebview` has not been set. Please ' + 'ensure that an implementation of `InAppWebViewPlatform` has been set to ' + '`InAppWebViewPlatform.instance` before use. For unit testing, ' + '`InAppWebViewPlatform.instance` can be set with your own test implementation.', + ); + final PlatformWebStorage webStorageStatic = + InAppWebViewPlatform.instance!.createPlatformWebStorageStatic(); + PlatformInterface.verify(webStorageStatic, _token); + return webStorageStatic; + } + /// Used by the platform implementation to create a new [PlatformWebStorage]. /// /// Should only be used by platform implementations because they can't extend @@ -67,26 +135,89 @@ abstract class PlatformWebStorage extends PlatformInterface ///{@template flutter_inappwebview_platform_interface.PlatformWebStorage.localStorage} ///Represents `window.localStorage`. ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage.localStorage.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) PlatformLocalStorage get localStorage => params.localStorage; ///{@template flutter_inappwebview_platform_interface.PlatformWebStorage.sessionStorage} ///Represents `window.sessionStorage`. ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage.sessionStorage.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) PlatformSessionStorage get sessionStorage => params.sessionStorage; ///{@template flutter_inappwebview_platform_interface.PlatformWebStorage.dispose} ///Disposes the web storage. ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorage.dispose.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) void dispose() { throw UnimplementedError( 'dispose is not implemented on the current platform'); } + + ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageCreationParams.isClassSupported} + bool isClassSupported({TargetPlatform? platform}) => + _PlatformWebStorageClassSupported.isClassSupported(platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorage.isPropertySupported} + ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isPropertySupported(dynamic property, {TargetPlatform? platform}) => + property is PlatformWebStorageCreationParamsProperty + ? params.isPropertySupported(property, platform: platform) + : _PlatformWebStoragePropertySupported.isPropertySupported(property, + platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorage.isMethodSupported} + ///Check if the given [method] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isMethodSupported(PlatformWebStorageMethod method, + {TargetPlatform? platform}) => + _PlatformWebStorageMethodSupported.isMethodSupported(method, + platform: platform); } /// Object specifying creation parameters for creating a [PlatformStorage]. /// /// Platform specific implementations can add additional fields by extending /// this class. +///{@template flutter_inappwebview_platform_interface.PlatformStorageCreationParams} +/// Object specifying creation parameters for creating a [PlatformStorage]. +/// +/// Platform specific implementations can add additional fields by extending +/// this class. +///{@endtemplate} +/// +///{@macro flutter_inappwebview_platform_interface.PlatformStorageCreationParams.supported_platforms} +@SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() +]) @immutable class PlatformStorageCreationParams { /// Used by the platform implementation to create a new [PlatformStorage]. @@ -94,25 +225,81 @@ class PlatformStorageCreationParams { {required this.controller, required this.webStorageType}); ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.controller} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.controller.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) final PlatformInAppWebViewController? controller; ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.webStorageType} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformStorage.webStorageType.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) final WebStorageType webStorageType; + + ///{@template flutter_inappwebview_platform_interface.PlatformStorageCreationParams.isClassSupported} + ///Check if the current class is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isClassSupported({TargetPlatform? platform}) => + _PlatformStorageCreationParamsClassSupported.isClassSupported( + platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformStorageCreationParams.isPropertySupported} + ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isPropertySupported(PlatformStorageCreationParamsProperty property, + {TargetPlatform? platform}) => + _PlatformStorageCreationParamsPropertySupported.isPropertySupported( + property, + platform: platform); } ///{@template flutter_inappwebview_platform_interface.PlatformStorage} ///Class that provides methods to manage the JavaScript [Storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage) object. ///It is used by [PlatformLocalStorage] and [PlatformSessionStorage]. ///{@endtemplate} +///{@macro flutter_inappwebview_platform_interface.PlatformStorage.supported_platforms} +@SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() +]) abstract mixin class PlatformStorage implements Disposable { ///{@template flutter_inappwebview_platform_interface.PlatformStorage.controller} ///Controller used to interact with storage. ///{@endtemplate} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) PlatformInAppWebViewController? get controller; ///{@template flutter_inappwebview_platform_interface.PlatformStorage.webStorageType} ///The web storage type: `window.sessionStorage` or `window.localStorage`. ///{@endtemplate} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) WebStorageType get webStorageType { throw UnimplementedError( 'webStorageType is not implemented on the current platform'); @@ -120,15 +307,16 @@ abstract mixin class PlatformStorage implements Disposable { ///{@template flutter_inappwebview_platform_interface.PlatformStorage.length} ///Returns an integer representing the number of data items stored in the Storage object. - /// - ///**NOTE for Web**: this method will have effect only if the iframe has the same origin. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS - ///- Web ///{@endtemplate} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform( + note: + 'This method has an effect only if the iframe has the same origin.'), + WindowsPlatform() + ]) Future length() { throw UnimplementedError( 'length is not implemented on the current platform'); @@ -136,15 +324,16 @@ abstract mixin class PlatformStorage implements Disposable { ///{@template flutter_inappwebview_platform_interface.PlatformStorage.setItem} ///When passed a [key] name and [value], will add that key to the storage, or update that key's value if it already exists. - /// - ///**NOTE for Web**: this method will have effect only if the iframe has the same origin. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS - ///- Web ///{@endtemplate} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform( + note: + 'This method has an effect only if the iframe has the same origin.'), + WindowsPlatform() + ]) Future setItem({required String key, required dynamic value}) { throw UnimplementedError( 'setItem is not implemented on the current platform'); @@ -152,15 +341,16 @@ abstract mixin class PlatformStorage implements Disposable { ///{@template flutter_inappwebview_platform_interface.PlatformStorage.getItem} ///When passed a [key] name, will return that key's value, or `null` if the key does not exist, in the given Storage object. - /// - ///**NOTE for Web**: this method will have effect only if the iframe has the same origin. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS - ///- Web ///{@endtemplate} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform( + note: + 'This method has an effect only if the iframe has the same origin.'), + WindowsPlatform() + ]) Future getItem({required String key}) { throw UnimplementedError( 'getItem is not implemented on the current platform'); @@ -168,15 +358,16 @@ abstract mixin class PlatformStorage implements Disposable { ///{@template flutter_inappwebview_platform_interface.PlatformStorage.removeItem} ///When passed a [key] name, will remove that key from the given Storage object if it exists. - /// - ///**NOTE for Web**: this method will have effect only if the iframe has the same origin. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS - ///- Web ///{@endtemplate} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform( + note: + 'This method has an effect only if the iframe has the same origin.'), + WindowsPlatform() + ]) Future removeItem({required String key}) { throw UnimplementedError( 'removeItem is not implemented on the current platform'); @@ -184,15 +375,16 @@ abstract mixin class PlatformStorage implements Disposable { ///{@template flutter_inappwebview_platform_interface.PlatformStorage.getItems} ///Returns the list of all items from the given Storage object. - /// - ///**NOTE for Web**: this method will have effect only if the iframe has the same origin. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS - ///- Web ///{@endtemplate} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform( + note: + 'This method has an effect only if the iframe has the same origin.'), + WindowsPlatform() + ]) Future> getItems() { throw UnimplementedError( 'getItems is not implemented on the current platform'); @@ -200,15 +392,16 @@ abstract mixin class PlatformStorage implements Disposable { ///{@template flutter_inappwebview_platform_interface.PlatformStorage.clear} ///Clears all keys stored in a given Storage object. - /// - ///**NOTE for Web**: this method will have effect only if the iframe has the same origin. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS - ///- Web ///{@endtemplate} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform( + note: + 'This method has an effect only if the iframe has the same origin.'), + WindowsPlatform() + ]) Future clear() { throw UnimplementedError( 'clear is not implemented on the current platform'); @@ -217,20 +410,28 @@ abstract mixin class PlatformStorage implements Disposable { ///{@template flutter_inappwebview_platform_interface.PlatformStorage.key} ///When passed a number [index], returns the name of the nth key in a given Storage object. ///The order of keys is user-agent defined, so you should not rely on it. - /// - ///**NOTE for Web**: this method will have effect only if the iframe has the same origin. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView - ///- iOS - ///- MacOS - ///- Web ///{@endtemplate} + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform( + note: + 'This method has an effect only if the iframe has the same origin.'), + WindowsPlatform() + ]) Future key({required int index}) { throw UnimplementedError('key is not implemented on the current platform'); } @override + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) void dispose() { throw UnimplementedError( 'dispose is not implemented on the current platform'); @@ -242,6 +443,13 @@ abstract mixin class PlatformStorage implements Disposable { /// Platform specific implementations can add additional fields by extending /// this class. @immutable +@SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() +]) class PlatformLocalStorageCreationParams extends PlatformStorageCreationParams { /// Used by the platform implementation to create a new [PlatformLocalStorage]. PlatformLocalStorageCreationParams( @@ -252,17 +460,32 @@ class PlatformLocalStorageCreationParams extends PlatformStorageCreationParams { controller: params.controller, webStorageType: WebStorageType.LOCAL_STORAGE); - /// Creates a [AndroidCookieManagerCreationParams] instance based on [PlatformCookieManagerCreationParams]. + /// Creates a [PlatformLocalStorageCreationParams] instance based on [PlatformLocalStorageCreationParams]. factory PlatformLocalStorageCreationParams.fromPlatformStorageCreationParams( PlatformStorageCreationParams params) { return PlatformLocalStorageCreationParams(params); } + + ///{@template flutter_inappwebview_platform_interface.PlatformLocalStorageCreationParams.isClassSupported} + ///Check if the current class is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isClassSupported({TargetPlatform? platform}) => + _PlatformLocalStorageCreationParamsClassSupported.isClassSupported( + platform: platform); } ///{@template flutter_inappwebview_platform_interface.PlatformLocalStorage} ///Class that provides methods to manage the JavaScript `window.localStorage` object. ///It used by [PlatformWebStorage]. ///{@endtemplate} +///{@macro flutter_inappwebview_platform_interface.PlatformLocalStorage.supported_platforms} +@SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() +]) abstract class PlatformLocalStorage extends PlatformInterface with PlatformStorage { /// Creates a new [PlatformLocalStorage] @@ -280,6 +503,21 @@ abstract class PlatformLocalStorage extends PlatformInterface return localStorage; } + /// Creates a new empty [PlatformLocalStorage] to access static methods. + factory PlatformLocalStorage.static() { + assert( + InAppWebViewPlatform.instance != null, + 'A platform implementation for `flutter_inappwebview` has not been set. Please ' + 'ensure that an implementation of `InAppWebViewPlatform` has been set to ' + '`WebViewPlatform.instance` before use. For unit testing, ' + '`WebViewPlatform.instance` can be set with your own test implementation.', + ); + final PlatformLocalStorage localStorageStatic = + InAppWebViewPlatform.instance!.createPlatformLocalStorageStatic(); + PlatformInterface.verify(localStorageStatic, _token); + return localStorageStatic; + } + /// Used by the platform implementation to create a new [PlatformLocalStorage]. /// /// Should only be used by platform implementations because they can't extend @@ -294,6 +532,106 @@ abstract class PlatformLocalStorage extends PlatformInterface @override WebStorageType get webStorageType => params.webStorageType; + + ///{@macro flutter_inappwebview_platform_interface.PlatformLocalStorage.isClassSupported} + bool isClassSupported({TargetPlatform? platform}) => + _PlatformLocalStorageClassSupported.isClassSupported(platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformLocalStorage.isPropertySupported} + ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isPropertySupported(PlatformStorageCreationParamsProperty property, + {TargetPlatform? platform}) => + params.isPropertySupported(property, platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformLocalStorage.isMethodSupported} + ///Check if the given [method] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isMethodSupported(PlatformLocalStorageMethod method, + {TargetPlatform? platform}) => + _PlatformLocalStorageMethodSupported.isMethodSupported(method, + platform: platform); + + @override + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) + Future length() => super.length(); + + @override + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) + Future setItem({required String key, required dynamic value}) => + super.setItem(key: key, value: value); + + @override + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) + Future getItem({required String key}) => super.getItem(key: key); + + @override + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) + Future removeItem({required String key}) => super.removeItem(key: key); + + @override + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) + Future> getItems() => super.getItems(); + + @override + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) + Future clear() => super.clear(); + + @override + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) + Future key({required int index}) => super.key(index: index); + + @override + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) + void dispose() => super.dispose(); } /// Object specifying creation parameters for creating a [PlatformSessionStorage]. @@ -301,6 +639,13 @@ abstract class PlatformLocalStorage extends PlatformInterface /// Platform specific implementations can add additional fields by extending /// this class. @immutable +@SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() +]) class PlatformSessionStorageCreationParams extends PlatformStorageCreationParams { /// Used by the platform implementation to create a new [PlatformSessionStorage]. @@ -312,17 +657,32 @@ class PlatformSessionStorageCreationParams controller: params.controller, webStorageType: WebStorageType.SESSION_STORAGE); - /// Creates a [AndroidCookieManagerCreationParams] instance based on [PlatformCookieManagerCreationParams]. + /// Creates a [PlatformSessionStorageCreationParams] instance based on [PlatformStorageCreationParams]. factory PlatformSessionStorageCreationParams.fromPlatformStorageCreationParams( PlatformStorageCreationParams params) { return PlatformSessionStorageCreationParams(params); } + + ///{@template flutter_inappwebview_platform_interface.PlatformSessionStorageCreationParams.isClassSupported} + ///Check if the current class is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isClassSupported({TargetPlatform? platform}) => + _PlatformSessionStorageCreationParamsClassSupported.isClassSupported( + platform: platform); } ///{@template flutter_inappwebview_platform_interface.PlatformSessionStorage} ///Class that provides methods to manage the JavaScript `window.sessionStorage` object. ///It used by [PlatformWebStorage]. ///{@endtemplate} +///{@macro flutter_inappwebview_platform_interface.PlatformSessionStorage.supported_platforms} +@SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() +]) abstract class PlatformSessionStorage extends PlatformInterface with PlatformStorage { /// Creates a new [PlatformSessionStorage] @@ -340,6 +700,21 @@ abstract class PlatformSessionStorage extends PlatformInterface return sessionStorage; } + /// Creates a new empty [PlatformSessionStorage] to access static methods. + factory PlatformSessionStorage.static() { + assert( + InAppWebViewPlatform.instance != null, + 'A platform implementation for `flutter_inappwebview` has not been set. Please ' + 'ensure that an implementation of `InAppWebViewPlatform` has been set to ' + '`WebViewPlatform.instance` before use. For unit testing, ' + '`WebViewPlatform.instance` can be set with your own test implementation.', + ); + final PlatformSessionStorage sessionStorageStatic = + InAppWebViewPlatform.instance!.createPlatformSessionStorageStatic(); + PlatformInterface.verify(sessionStorageStatic, _token); + return sessionStorageStatic; + } + /// Used by the platform implementation to create a new [PlatformSessionStorage]. /// /// Should only be used by platform implementations because they can't extend @@ -354,4 +729,105 @@ abstract class PlatformSessionStorage extends PlatformInterface @override WebStorageType get webStorageType => params.webStorageType; + + ///{@macro flutter_inappwebview_platform_interface.PlatformSessionStorage.isClassSupported} + bool isClassSupported({TargetPlatform? platform}) => + _PlatformSessionStorageClassSupported.isClassSupported( + platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformSessionStorage.isPropertySupported} + ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isPropertySupported(PlatformStorageCreationParamsProperty property, + {TargetPlatform? platform}) => + params.isPropertySupported(property, platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformSessionStorage.isMethodSupported} + ///Check if the given [method] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isMethodSupported(PlatformSessionStorageMethod method, + {TargetPlatform? platform}) => + _PlatformSessionStorageMethodSupported.isMethodSupported(method, + platform: platform); + + @override + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) + Future length() => super.length(); + + @override + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) + Future setItem({required String key, required dynamic value}) => + super.setItem(key: key, value: value); + + @override + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) + Future getItem({required String key}) => super.getItem(key: key); + + @override + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) + Future removeItem({required String key}) => super.removeItem(key: key); + + @override + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) + Future> getItems() => super.getItems(); + + @override + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) + Future clear() => super.clear(); + + @override + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) + Future key({required int index}) => super.key(index: index); + + @override + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), + WebPlatform(), + WindowsPlatform() + ]) + void dispose() => super.dispose(); } diff --git a/flutter_inappwebview_platform_interface/lib/src/web_storage/platform_web_storage.g.dart b/flutter_inappwebview_platform_interface/lib/src/web_storage/platform_web_storage.g.dart new file mode 100644 index 000000000..c92dc5893 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/web_storage/platform_web_storage.g.dart @@ -0,0 +1,857 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'platform_web_storage.dart'; + +// ************************************************************************** +// SupportedPlatformsGenerator +// ************************************************************************** + +extension _PlatformWebStorageCreationParamsClassSupported + on PlatformWebStorageCreationParams { + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageCreationParams.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformWebStorageCreationParams.isClassSupported] method to check if this class is supported at runtime. + ///{@endtemplate} + static bool isClassSupported({TargetPlatform? platform}) { + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + } +} + +///List of [PlatformWebStorageCreationParams]'s properties that can be used to check i they are supported or not by the current platform. +enum PlatformWebStorageCreationParamsProperty { + ///Can be used to check if the [PlatformWebStorageCreationParams.localStorage] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageCreationParams.localStorage.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformWebStorageCreationParams.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + localStorage, + + ///Can be used to check if the [PlatformWebStorageCreationParams.sessionStorage] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageCreationParams.sessionStorage.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformWebStorageCreationParams.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + sessionStorage, +} + +extension _PlatformWebStorageCreationParamsPropertySupported + on PlatformWebStorageCreationParams { + static bool isPropertySupported( + PlatformWebStorageCreationParamsProperty property, + {TargetPlatform? platform}) { + switch (property) { + case PlatformWebStorageCreationParamsProperty.localStorage: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + case PlatformWebStorageCreationParamsProperty.sessionStorage: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + } + } +} + +extension _PlatformWebStorageClassSupported on PlatformWebStorage { + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorage.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformWebStorage.isClassSupported] method to check if this class is supported at runtime. + ///{@endtemplate} + static bool isClassSupported({TargetPlatform? platform}) { + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + } +} + +///List of [PlatformWebStorage]'s properties that can be used to check i they are supported or not by the current platform. +enum PlatformWebStorageProperty { + ///Can be used to check if the [PlatformWebStorage.localStorage] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorage.localStorage.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformWebStorage.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + localStorage, + + ///Can be used to check if the [PlatformWebStorage.sessionStorage] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorage.sessionStorage.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformWebStorage.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + sessionStorage, +} + +extension _PlatformWebStoragePropertySupported on PlatformWebStorage { + static bool isPropertySupported(PlatformWebStorageProperty property, + {TargetPlatform? platform}) { + switch (property) { + case PlatformWebStorageProperty.localStorage: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + case PlatformWebStorageProperty.sessionStorage: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + } + } +} + +///List of [PlatformWebStorage]'s methods that can be used to check if they are supported or not by the current platform. +enum PlatformWebStorageMethod { + ///Can be used to check if the [PlatformWebStorage.dispose] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorage.dispose.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformWebStorage.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + dispose, +} + +extension _PlatformWebStorageMethodSupported on PlatformWebStorage { + static bool isMethodSupported(PlatformWebStorageMethod method, + {TargetPlatform? platform}) { + switch (method) { + case PlatformWebStorageMethod.dispose: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + } + } +} + +extension _PlatformStorageCreationParamsClassSupported + on PlatformStorageCreationParams { + ///{@template flutter_inappwebview_platform_interface.PlatformStorageCreationParams.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformStorageCreationParams.isClassSupported] method to check if this class is supported at runtime. + ///{@endtemplate} + static bool isClassSupported({TargetPlatform? platform}) { + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + } +} + +///List of [PlatformStorageCreationParams]'s properties that can be used to check i they are supported or not by the current platform. +enum PlatformStorageCreationParamsProperty { + ///Can be used to check if the [PlatformStorageCreationParams.controller] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformStorageCreationParams.controller.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformStorageCreationParams.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + controller, + + ///Can be used to check if the [PlatformStorageCreationParams.webStorageType] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformStorageCreationParams.webStorageType.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformStorageCreationParams.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + webStorageType, +} + +extension _PlatformStorageCreationParamsPropertySupported + on PlatformStorageCreationParams { + static bool isPropertySupported( + PlatformStorageCreationParamsProperty property, + {TargetPlatform? platform}) { + switch (property) { + case PlatformStorageCreationParamsProperty.controller: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + case PlatformStorageCreationParamsProperty.webStorageType: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + } + } +} + +extension _PlatformLocalStorageCreationParamsClassSupported + on PlatformLocalStorageCreationParams { + ///{@template flutter_inappwebview_platform_interface.PlatformLocalStorageCreationParams.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformLocalStorageCreationParams.isClassSupported] method to check if this class is supported at runtime. + ///{@endtemplate} + static bool isClassSupported({TargetPlatform? platform}) { + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + } +} + +extension _PlatformLocalStorageClassSupported on PlatformLocalStorage { + ///{@template flutter_inappwebview_platform_interface.PlatformLocalStorage.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformLocalStorage.isClassSupported] method to check if this class is supported at runtime. + ///{@endtemplate} + static bool isClassSupported({TargetPlatform? platform}) { + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + } +} + +///List of [PlatformLocalStorage]'s methods that can be used to check if they are supported or not by the current platform. +enum PlatformLocalStorageMethod { + ///Can be used to check if the [PlatformLocalStorage.clear] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformLocalStorage.clear.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformLocalStorage.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + clear, + + ///Can be used to check if the [PlatformLocalStorage.dispose] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformLocalStorage.dispose.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformLocalStorage.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + dispose, + + ///Can be used to check if the [PlatformLocalStorage.getItem] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformLocalStorage.getItem.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [key]: all platforms + /// + ///Use the [PlatformLocalStorage.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + getItem, + + ///Can be used to check if the [PlatformLocalStorage.getItems] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformLocalStorage.getItems.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformLocalStorage.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + getItems, + + ///Can be used to check if the [PlatformLocalStorage.key] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformLocalStorage.key.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [index]: all platforms + /// + ///Use the [PlatformLocalStorage.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + key, + + ///Can be used to check if the [PlatformLocalStorage.length] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformLocalStorage.length.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformLocalStorage.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + length, + + ///Can be used to check if the [PlatformLocalStorage.removeItem] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformLocalStorage.removeItem.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [key]: all platforms + /// + ///Use the [PlatformLocalStorage.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + removeItem, + + ///Can be used to check if the [PlatformLocalStorage.setItem] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformLocalStorage.setItem.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [key]: all platforms + ///- [value]: all platforms + /// + ///Use the [PlatformLocalStorage.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + setItem, +} + +extension _PlatformLocalStorageMethodSupported on PlatformLocalStorage { + static bool isMethodSupported(PlatformLocalStorageMethod method, + {TargetPlatform? platform}) { + switch (method) { + case PlatformLocalStorageMethod.clear: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + case PlatformLocalStorageMethod.dispose: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + case PlatformLocalStorageMethod.getItem: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + case PlatformLocalStorageMethod.getItems: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + case PlatformLocalStorageMethod.key: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + case PlatformLocalStorageMethod.length: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + case PlatformLocalStorageMethod.removeItem: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + case PlatformLocalStorageMethod.setItem: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + } + } +} + +extension _PlatformSessionStorageCreationParamsClassSupported + on PlatformSessionStorageCreationParams { + ///{@template flutter_inappwebview_platform_interface.PlatformSessionStorageCreationParams.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformSessionStorageCreationParams.isClassSupported] method to check if this class is supported at runtime. + ///{@endtemplate} + static bool isClassSupported({TargetPlatform? platform}) { + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + } +} + +extension _PlatformSessionStorageClassSupported on PlatformSessionStorage { + ///{@template flutter_inappwebview_platform_interface.PlatformSessionStorage.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformSessionStorage.isClassSupported] method to check if this class is supported at runtime. + ///{@endtemplate} + static bool isClassSupported({TargetPlatform? platform}) { + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + } +} + +///List of [PlatformSessionStorage]'s methods that can be used to check if they are supported or not by the current platform. +enum PlatformSessionStorageMethod { + ///Can be used to check if the [PlatformSessionStorage.clear] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformSessionStorage.clear.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformSessionStorage.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + clear, + + ///Can be used to check if the [PlatformSessionStorage.dispose] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformSessionStorage.dispose.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformSessionStorage.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + dispose, + + ///Can be used to check if the [PlatformSessionStorage.getItem] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformSessionStorage.getItem.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [key]: all platforms + /// + ///Use the [PlatformSessionStorage.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + getItem, + + ///Can be used to check if the [PlatformSessionStorage.getItems] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformSessionStorage.getItems.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformSessionStorage.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + getItems, + + ///Can be used to check if the [PlatformSessionStorage.key] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformSessionStorage.key.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [index]: all platforms + /// + ///Use the [PlatformSessionStorage.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + key, + + ///Can be used to check if the [PlatformSessionStorage.length] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformSessionStorage.length.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///Use the [PlatformSessionStorage.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + length, + + ///Can be used to check if the [PlatformSessionStorage.removeItem] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformSessionStorage.removeItem.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [key]: all platforms + /// + ///Use the [PlatformSessionStorage.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + removeItem, + + ///Can be used to check if the [PlatformSessionStorage.setItem] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformSessionStorage.setItem.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView + ///- macOS WKWebView + ///- Web \ but requires same origin + ///- Windows WebView2 + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [key]: all platforms + ///- [value]: all platforms + /// + ///Use the [PlatformSessionStorage.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + setItem, +} + +extension _PlatformSessionStorageMethodSupported on PlatformSessionStorage { + static bool isMethodSupported(PlatformSessionStorageMethod method, + {TargetPlatform? platform}) { + switch (method) { + case PlatformSessionStorageMethod.clear: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + case PlatformSessionStorageMethod.dispose: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + case PlatformSessionStorageMethod.getItem: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + case PlatformSessionStorageMethod.getItems: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + case PlatformSessionStorageMethod.key: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + case PlatformSessionStorageMethod.length: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + case PlatformSessionStorageMethod.removeItem: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + case PlatformSessionStorageMethod.setItem: + return kIsWeb && platform == null + ? true + : ((kIsWeb && platform != null) || !kIsWeb) && + [ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + TargetPlatform.windows + ].contains(platform ?? defaultTargetPlatform); + } + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/web_storage/platform_web_storage_manager.dart b/flutter_inappwebview_platform_interface/lib/src/web_storage/platform_web_storage_manager.dart index 6f2131ed4..fb24cc1cf 100755 --- a/flutter_inappwebview_platform_interface/lib/src/web_storage/platform_web_storage_manager.dart +++ b/flutter_inappwebview_platform_interface/lib/src/web_storage/platform_web_storage_manager.dart @@ -1,35 +1,62 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import '../inappwebview_platform.dart'; import '../types/main.dart'; +part 'platform_web_storage_manager.g.dart'; + +///{@template flutter_inappwebview_platform_interface.PlatformWebStorageManagerCreationParams} /// Object specifying creation parameters for creating a [PlatformWebStorageManager]. /// /// Platform specific implementations can add additional fields by extending /// this class. +///{@endtemplate} +/// +///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManagerCreationParams.supported_platforms} +@SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(available: '9.0'), + MacOSPlatform(), +]) @immutable class PlatformWebStorageManagerCreationParams { /// Used by the platform implementation to create a new [PlatformWebStorageManager]. const PlatformWebStorageManagerCreationParams(); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageManagerCreationParams.isClassSupported} + ///Check if the current class is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isClassSupported({TargetPlatform? platform}) => + _PlatformWebStorageManagerCreationParamsClassSupported.isClassSupported( + platform: platform); } ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageManager} ///Class that implements a singleton object (shared instance) which manages the web storage used by WebView instances. -///On Android, it is implemented using [WebStorage](https://developer.android.com/reference/android/webkit/WebStorage.html). -///On iOS and MacOS, it is implemented using [WKWebsiteDataStore.default()](https://developer.apple.com/documentation/webkit/wkwebsitedatastore). -/// -///**NOTE for iOS**: available from iOS 9.0+. -/// -///**Officially Supported Platforms/Implementations**: -///- Android native WebView -///- iOS -///- MacOS ///{@endtemplate} +/// +///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.supported_platforms} +@SupportedPlatforms(platforms: [ + AndroidPlatform( + apiName: 'WebStorage', + apiUrl: + 'https://developer.android.com/reference/android/webkit/WebStorage.html'), + IOSPlatform( + apiName: 'WKWebsiteDataStore', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wkwebsitedatastore', + available: '9.0'), + MacOSPlatform( + apiName: 'WKWebsiteDataStore', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wkwebsitedatastore'), +]) abstract class PlatformWebStorageManager extends PlatformInterface { - /// Creates a new [PlatformCookieManager] + /// Creates a new [PlatformWebStorageManager] factory PlatformWebStorageManager( PlatformWebStorageManagerCreationParams params) { assert( @@ -39,10 +66,25 @@ abstract class PlatformWebStorageManager extends PlatformInterface { '`WebViewPlatform.instance` before use. For unit testing, ' '`WebViewPlatform.instance` can be set with your own test implementation.', ); - final PlatformWebStorageManager cookieManager = + final PlatformWebStorageManager webStorageManager = InAppWebViewPlatform.instance!.createPlatformWebStorageManager(params); - PlatformInterface.verify(cookieManager, _token); - return cookieManager; + PlatformInterface.verify(webStorageManager, _token); + return webStorageManager; + } + + /// Creates a new [PlatformWebStorageManager] to access static methods. + factory PlatformWebStorageManager.static() { + assert( + InAppWebViewPlatform.instance != null, + 'A platform implementation for `flutter_inappwebview` has not been set. Please ' + 'ensure that an implementation of `InAppWebViewPlatform` has been set to ' + '`WebViewPlatform.instance` before use. For unit testing, ' + '`WebViewPlatform.instance` can be set with your own test implementation.', + ); + final PlatformWebStorageManager webStorageManagerStatic = + InAppWebViewPlatform.instance!.createPlatformWebStorageManagerStatic(); + PlatformInterface.verify(webStorageManagerStatic, _token); + return webStorageManagerStatic; } /// Used by the platform implementation to create a new @@ -60,10 +102,15 @@ abstract class PlatformWebStorageManager extends PlatformInterface { ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageManager.getOrigins} ///Gets the origins currently using either the Application Cache or Web SQL Database APIs. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebStorage.getOrigins](https://developer.android.com/reference/android/webkit/WebStorage#getOrigins(android.webkit.ValueCallback%3Cjava.util.Map%3E))) ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.getOrigins.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform( + apiName: 'WebStorage.getOrigins', + apiUrl: + 'https://developer.android.com/reference/android/webkit/WebStorage#getOrigins(android.webkit.ValueCallback%3Cjava.util.Map%3E)') + ]) Future> getOrigins() { throw UnimplementedError( 'getOrigins is not implemented on the current platform'); @@ -72,10 +119,15 @@ abstract class PlatformWebStorageManager extends PlatformInterface { ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageManager.deleteAllData} ///Clears all storage currently being used by the JavaScript storage APIs. ///This includes the Application Cache, Web SQL Database and the HTML5 Web Storage APIs. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebStorage.deleteAllData](https://developer.android.com/reference/android/webkit/WebStorage#deleteAllData())) ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.deleteAllData.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform( + apiName: 'WebStorage.deleteAllData', + apiUrl: + 'https://developer.android.com/reference/android/webkit/WebStorage#deleteAllData()') + ]) Future deleteAllData() { throw UnimplementedError( 'deleteAllData is not implemented on the current platform'); @@ -84,10 +136,15 @@ abstract class PlatformWebStorageManager extends PlatformInterface { ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageManager.deleteOrigin} ///Clears the storage currently being used by both the Application Cache and Web SQL Database APIs by the given [origin]. ///The origin is specified using its string representation. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebStorage.deleteOrigin](https://developer.android.com/reference/android/webkit/WebStorage#deleteOrigin(java.lang.String))) ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.deleteOrigin.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform( + apiName: 'WebStorage.deleteOrigin', + apiUrl: + 'https://developer.android.com/reference/android/webkit/WebStorage#deleteOrigin(java.lang.String)') + ]) Future deleteOrigin({required String origin}) { throw UnimplementedError( 'deleteOrigin is not implemented on the current platform'); @@ -97,10 +154,15 @@ abstract class PlatformWebStorageManager extends PlatformInterface { ///Gets the storage quota for the Web SQL Database API for the given [origin]. ///The quota is given in bytes and the origin is specified using its string representation. ///Note that a quota is not enforced on a per-origin basis for the Application Cache API. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebStorage.getQuotaForOrigin](https://developer.android.com/reference/android/webkit/WebStorage#getQuotaForOrigin(java.lang.String,%20android.webkit.ValueCallback%3Cjava.lang.Long%3E))) ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.getQuotaForOrigin.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform( + apiName: 'WebStorage.getQuotaForOrigin', + apiUrl: + 'https://developer.android.com/reference/android/webkit/WebStorage#getQuotaForOrigin(java.lang.String,%20android.webkit.ValueCallback%3Cjava.lang.Long%3E)') + ]) Future getQuotaForOrigin({required String origin}) { throw UnimplementedError( 'getQuotaForOrigin is not implemented on the current platform'); @@ -109,10 +171,15 @@ abstract class PlatformWebStorageManager extends PlatformInterface { ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageManager.getUsageForOrigin} ///Gets the amount of storage currently being used by both the Application Cache and Web SQL Database APIs by the given [origin]. ///The amount is given in bytes and the origin is specified using its string representation. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Android native WebView ([Official API - WebStorage.getUsageForOrigin](https://developer.android.com/reference/android/webkit/WebStorage#getUsageForOrigin(java.lang.String,%20android.webkit.ValueCallback%3Cjava.lang.Long%3E))) ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.getUsageForOrigin.supported_platforms} + @SupportedPlatforms(platforms: [ + AndroidPlatform( + apiName: 'WebStorage.getUsageForOrigin', + apiUrl: + 'https://developer.android.com/reference/android/webkit/WebStorage#getUsageForOrigin(java.lang.String,%20android.webkit.ValueCallback%3Cjava.lang.Long%3E)') + ]) Future getUsageForOrigin({required String origin}) { throw UnimplementedError( 'getUsageForOrigin is not implemented on the current platform'); @@ -122,11 +189,20 @@ abstract class PlatformWebStorageManager extends PlatformInterface { ///Fetches data records containing the given website data types. /// ///[dataTypes] represents the website data types to fetch records for. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - WKWebsiteDataStore.fetchDataRecords](https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532932-fetchdatarecords)) - ///- MacOS ([Official API - WKWebsiteDataStore.fetchDataRecords](https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532932-fetchdatarecords)) ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.fetchDataRecords.supported_platforms} + @SupportedPlatforms(platforms: [ + IOSPlatform( + available: '9.0', + apiName: 'WKWebsiteDataStore.fetchDataRecords', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532932-fetchdatarecords'), + MacOSPlatform( + apiName: 'WKWebsiteDataStore.fetchDataRecords', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532932-fetchdatarecords'), + ]) Future> fetchDataRecords( {required Set dataTypes}) { throw UnimplementedError( @@ -139,11 +215,20 @@ abstract class PlatformWebStorageManager extends PlatformInterface { ///[dataTypes] represents the website data types that should be removed. /// ///[dataRecords] represents the website data records to delete website data for. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - WKWebsiteDataStore.removeData](https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532936-removedata)) - ///- MacOS ([Official API - WKWebsiteDataStore.removeData](https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532936-removedata)) ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.removeDataFor.supported_platforms} + @SupportedPlatforms(platforms: [ + IOSPlatform( + available: '9.0', + apiName: 'WKWebsiteDataStore.removeData', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532936-removedata'), + MacOSPlatform( + apiName: 'WKWebsiteDataStore.removeData', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532936-removedata'), + ]) Future removeDataFor( {required Set dataTypes, required List dataRecords}) { @@ -157,14 +242,38 @@ abstract class PlatformWebStorageManager extends PlatformInterface { ///[dataTypes] represents the website data types that should be removed. /// ///[date] represents a date. All website data modified after this date will be removed. - /// - ///**Officially Supported Platforms/Implementations**: - ///- iOS ([Official API - WKWebsiteDataStore.removeData](https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532938-removedata)) - ///- MacOS ([Official API - WKWebsiteDataStore.removeData](https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532938-removedata)) ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebStorageManager.removeDataModifiedSince.supported_platforms} + @SupportedPlatforms(platforms: [ + IOSPlatform( + available: '9.0', + apiName: 'WKWebsiteDataStore.removeData', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532938-removedata'), + MacOSPlatform( + apiName: 'WKWebsiteDataStore.removeData', + apiUrl: + 'https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532938-removedata'), + ]) Future removeDataModifiedSince( {required Set dataTypes, required DateTime date}) { throw UnimplementedError( 'removeDataModifiedSince is not implemented on the current platform'); } + + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageManager.isClassSupported} + ///Check if the current class is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isClassSupported({TargetPlatform? platform}) => + _PlatformWebStorageManagerClassSupported.isClassSupported( + platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageManager.isMethodSupported} + ///Check if the given [method] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isMethodSupported(PlatformWebStorageManagerMethod method, + {TargetPlatform? platform}) => + _PlatformWebStorageManagerMethodSupported.isMethodSupported(method, + platform: platform); } diff --git a/flutter_inappwebview_platform_interface/lib/src/web_storage/platform_web_storage_manager.g.dart b/flutter_inappwebview_platform_interface/lib/src/web_storage/platform_web_storage_manager.g.dart new file mode 100644 index 000000000..3c8f47055 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/web_storage/platform_web_storage_manager.g.dart @@ -0,0 +1,198 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'platform_web_storage_manager.dart'; + +// ************************************************************************** +// SupportedPlatformsGenerator +// ************************************************************************** + +extension _PlatformWebStorageManagerCreationParamsClassSupported + on PlatformWebStorageManagerCreationParams { + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageManagerCreationParams.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView + ///- iOS WKWebView 9.0+ + ///- macOS WKWebView + /// + ///Use the [PlatformWebStorageManagerCreationParams.isClassSupported] method to check if this class is supported at runtime. + ///{@endtemplate} + static bool isClassSupported({TargetPlatform? platform}) { + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.android, TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + } +} + +extension _PlatformWebStorageManagerClassSupported + on PlatformWebStorageManager { + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageManager.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView ([Official API - WebStorage](https://developer.android.com/reference/android/webkit/WebStorage.html)) + ///- iOS WKWebView 9.0+ ([Official API - WKWebsiteDataStore](https://developer.apple.com/documentation/webkit/wkwebsitedatastore)) + ///- macOS WKWebView ([Official API - WKWebsiteDataStore](https://developer.apple.com/documentation/webkit/wkwebsitedatastore)) + /// + ///Use the [PlatformWebStorageManager.isClassSupported] method to check if this class is supported at runtime. + ///{@endtemplate} + static bool isClassSupported({TargetPlatform? platform}) { + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.android, TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + } +} + +///List of [PlatformWebStorageManager]'s methods that can be used to check if they are supported or not by the current platform. +enum PlatformWebStorageManagerMethod { + ///Can be used to check if the [PlatformWebStorageManager.deleteAllData] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageManager.deleteAllData.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView ([Official API - WebStorage.deleteAllData](https://developer.android.com/reference/android/webkit/WebStorage#deleteAllData())) + /// + ///Use the [PlatformWebStorageManager.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + deleteAllData, + + ///Can be used to check if the [PlatformWebStorageManager.deleteOrigin] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageManager.deleteOrigin.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView ([Official API - WebStorage.deleteOrigin](https://developer.android.com/reference/android/webkit/WebStorage#deleteOrigin(java.lang.String))) + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [origin]: all platforms + /// + ///Use the [PlatformWebStorageManager.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + deleteOrigin, + + ///Can be used to check if the [PlatformWebStorageManager.fetchDataRecords] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageManager.fetchDataRecords.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView 9.0+ ([Official API - WKWebsiteDataStore.fetchDataRecords](https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532932-fetchdatarecords)) + ///- macOS WKWebView ([Official API - WKWebsiteDataStore.fetchDataRecords](https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532932-fetchdatarecords)) + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [dataTypes]: all platforms + /// + ///Use the [PlatformWebStorageManager.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + fetchDataRecords, + + ///Can be used to check if the [PlatformWebStorageManager.getOrigins] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageManager.getOrigins.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView ([Official API - WebStorage.getOrigins](https://developer.android.com/reference/android/webkit/WebStorage#getOrigins(android.webkit.ValueCallback%3Cjava.util.Map%3E))) + /// + ///Use the [PlatformWebStorageManager.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + getOrigins, + + ///Can be used to check if the [PlatformWebStorageManager.getQuotaForOrigin] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageManager.getQuotaForOrigin.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView ([Official API - WebStorage.getQuotaForOrigin](https://developer.android.com/reference/android/webkit/WebStorage#getQuotaForOrigin(java.lang.String,%20android.webkit.ValueCallback%3Cjava.lang.Long%3E))) + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [origin]: all platforms + /// + ///Use the [PlatformWebStorageManager.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + getQuotaForOrigin, + + ///Can be used to check if the [PlatformWebStorageManager.getUsageForOrigin] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageManager.getUsageForOrigin.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Android WebView ([Official API - WebStorage.getUsageForOrigin](https://developer.android.com/reference/android/webkit/WebStorage#getUsageForOrigin(java.lang.String,%20android.webkit.ValueCallback%3Cjava.lang.Long%3E))) + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [origin]: all platforms + /// + ///Use the [PlatformWebStorageManager.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + getUsageForOrigin, + + ///Can be used to check if the [PlatformWebStorageManager.removeDataFor] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageManager.removeDataFor.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView 9.0+ ([Official API - WKWebsiteDataStore.removeData](https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532936-removedata)) + ///- macOS WKWebView ([Official API - WKWebsiteDataStore.removeData](https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532936-removedata)) + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [dataTypes]: all platforms + ///- [dataRecords]: all platforms + /// + ///Use the [PlatformWebStorageManager.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + removeDataFor, + + ///Can be used to check if the [PlatformWebStorageManager.removeDataModifiedSince] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebStorageManager.removeDataModifiedSince.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- iOS WKWebView 9.0+ ([Official API - WKWebsiteDataStore.removeData](https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532938-removedata)) + ///- macOS WKWebView ([Official API - WKWebsiteDataStore.removeData](https://developer.apple.com/documentation/webkit/wkwebsitedatastore/1532938-removedata)) + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [dataTypes]: all platforms + ///- [date]: all platforms + /// + ///Use the [PlatformWebStorageManager.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + removeDataModifiedSince, +} + +extension _PlatformWebStorageManagerMethodSupported + on PlatformWebStorageManager { + static bool isMethodSupported(PlatformWebStorageManagerMethod method, + {TargetPlatform? platform}) { + switch (method) { + case PlatformWebStorageManagerMethod.deleteAllData: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.android] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebStorageManagerMethod.deleteOrigin: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.android] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebStorageManagerMethod.fetchDataRecords: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebStorageManagerMethod.getOrigins: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.android] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebStorageManagerMethod.getQuotaForOrigin: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.android] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebStorageManagerMethod.getUsageForOrigin: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.android] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebStorageManagerMethod.removeDataFor: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebStorageManagerMethod.removeDataModifiedSince: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.iOS, TargetPlatform.macOS] + .contains(platform ?? defaultTargetPlatform); + } + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/web_storage/web_storage_item.dart b/flutter_inappwebview_platform_interface/lib/src/web_storage/web_storage_item.dart index 4a2e3bce1..1e1fc0957 100644 --- a/flutter_inappwebview_platform_interface/lib/src/web_storage/web_storage_item.dart +++ b/flutter_inappwebview_platform_interface/lib/src/web_storage/web_storage_item.dart @@ -1,5 +1,7 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; +import '../types/enum_method.dart'; + part 'web_storage_item.g.dart'; ///Class that represents a single web storage item of the JavaScript `window.sessionStorage` and `window.localStorage` objects. diff --git a/flutter_inappwebview_platform_interface/lib/src/web_storage/web_storage_item.g.dart b/flutter_inappwebview_platform_interface/lib/src/web_storage/web_storage_item.g.dart index ec2f686b2..b6a6a9088 100644 --- a/flutter_inappwebview_platform_interface/lib/src/web_storage/web_storage_item.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/web_storage/web_storage_item.g.dart @@ -16,7 +16,8 @@ class WebStorageItem { WebStorageItem({this.key, this.value}); ///Gets a possible [WebStorageItem] instance from a [Map] value. - static WebStorageItem? fromMap(Map? map) { + static WebStorageItem? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -28,7 +29,7 @@ class WebStorageItem { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "key": key, "value": value, diff --git a/flutter_inappwebview_platform_interface/lib/src/webview_environment/platform_webview_environment.dart b/flutter_inappwebview_platform_interface/lib/src/webview_environment/platform_webview_environment.dart index 367886928..5521c1766 100644 --- a/flutter_inappwebview_platform_interface/lib/src/webview_environment/platform_webview_environment.dart +++ b/flutter_inappwebview_platform_interface/lib/src/webview_environment/platform_webview_environment.dart @@ -1,29 +1,59 @@ import 'package:flutter/foundation.dart'; +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import '../debug_logging_settings.dart'; import '../inappwebview_platform.dart'; +import '../in_app_webview/platform_webview.dart'; +import '../types/browser_process_info.dart'; import '../types/disposable.dart'; +import '../types/browser_process_exited_detail.dart'; +import '../types/browser_process_infos_changed_detail.dart'; +import '../types/webview_interface.dart'; import 'webview_environment_settings.dart'; +part 'platform_webview_environment.g.dart'; + /// Object specifying creation parameters for creating a [PlatformWebViewEnvironment]. /// /// Platform specific implementations can add additional fields by extending /// this class. +@SupportedPlatforms(platforms: [WindowsPlatform()]) @immutable class PlatformWebViewEnvironmentCreationParams { /// Used by the platform implementation to create a new [PlatformWebViewEnvironment]. const PlatformWebViewEnvironmentCreationParams({this.settings}); - ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.settings} + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironmentCreationParams.settings} + /// WebView Environment settings. + ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironmentCreationParams.settings.supported_platforms} + @SupportedPlatforms(platforms: [WindowsPlatform()]) final WebViewEnvironmentSettings? settings; + + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironmentCreationParams.isClassSupported} + ///Check if the current class is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isClassSupported({TargetPlatform? platform}) => + _PlatformWebViewEnvironmentCreationParamsClassSupported.isClassSupported( + platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironmentCreationParams.isPropertySupported} + ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isPropertySupported( + PlatformWebViewEnvironmentCreationParamsProperty property, + {TargetPlatform? platform}) => + _PlatformWebViewEnvironmentCreationParamsPropertySupported + .isPropertySupported(property, platform: platform); } ///Controls a WebView Environment used by WebView instances. ///Use [dispose] when not needed anymore to release references. /// -///**Officially Supported Platforms/Implementations**: -///- Windows +///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.supported_platforms} +@SupportedPlatforms(platforms: [WindowsPlatform()]) abstract class PlatformWebViewEnvironment extends PlatformInterface implements Disposable { ///Debug settings used by [PlatformWebViewEnvironment]. @@ -76,23 +106,87 @@ abstract class PlatformWebViewEnvironment extends PlatformInterface ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.id} /// WebView Environment ID. ///{@endtemplate} + @SupportedPlatforms(platforms: [WindowsPlatform()]) String get id => throw UnimplementedError('id is not implemented on the current platform'); - ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.settings} - /// WebView Environment settings. - ///{@endtemplate} + ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironmentCreationParams.settings} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironmentCreationParams.settings.supported_platforms} WebViewEnvironmentSettings? get settings => params.settings; + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.isInterfaceSupported} + ///Returns `true` if the WebView Environment supports the specified [interface], otherwise `false`. + ///Only the ones related to [WebViewInterface.ICoreWebView2Environment] are valid interfaces to check; + ///otherwise, it will always return `false`. + ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.isInterfaceSupported.supported_platforms} + @SupportedPlatforms(platforms: [WindowsPlatform()]) + Future isInterfaceSupported(WebViewInterface interface) async { + throw UnimplementedError( + 'isInterfaceSupported is not implemented on the current platform'); + } + + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getProcessInfos} + ///Returns a list of all process using same user data folder except for crashpad process. + ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getProcessInfos.supported_platforms} + @SupportedPlatforms(platforms: [ + WindowsPlatform( + available: '1.0.1108.44+', + apiName: 'ICoreWebView2Environment8.GetProcessInfos', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environment8?view=webview2-1.0.2849.39#getprocessinfos') + ]) + Future> getProcessInfos() async { + throw UnimplementedError( + 'getProcessInfos is not implemented on the current platform'); + } + + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getProcessInfos} + ///Returns the path of the folder where minidump files are written. + /// + ///Whenever a WebView2 process crashes, a crash dump file will be created in the crash dump folder. + ///The crash dump format is minidump files. + ///Please see [Minidump Files documentation](https://learn.microsoft.com/en-us/windows/win32/debug/minidump-files) for detailed information. + ///Normally when a single child process fails, a minidump will be generated and written to disk, + ///then the [PlatformWebViewCreationParams.onProcessFailed] event is raised. + ///But for unexpected crashes, a minidump file might + ///not be generated at all, despite whether [PlatformWebViewCreationParams.onProcessFailed] event is raised. + ///If there are multiple process failures at once, multiple minidump files could be generated. + ///Thus [getFailureReportFolderPath] could contain old minidump files that are + ///not associated with a specific [PlatformWebViewCreationParams.onProcessFailed] event. + ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getFailureReportFolderPath.supported_platforms} + @SupportedPlatforms(platforms: [ + WindowsPlatform( + available: '1.0.1518.46+', + apiName: 'ICoreWebView2Environment11.get_FailureReportFolderPath', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environment11?view=webview2-1.0.2849.39#get_failurereportfolderpath') + ]) + Future getFailureReportFolderPath() async { + throw UnimplementedError( + 'getFailureReportFolderPath is not implemented on the current platform'); + } + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.create} ///Creates the [PlatformWebViewEnvironment] using [settings]. /// ///Check https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#createcorewebview2environmentwithoptions ///for more info. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - CreateCoreWebView2EnvironmentWithOptions](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#createcorewebview2environmentwithoptions)) ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.create.supported_platforms} + @SupportedPlatforms(platforms: [ + WindowsPlatform( + apiName: 'CreateCoreWebView2EnvironmentWithOptions', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#createcorewebview2environmentwithoptions') + ]) Future create( {WebViewEnvironmentSettings? settings}) { throw UnimplementedError( @@ -106,10 +200,15 @@ abstract class PlatformWebViewEnvironment extends PlatformInterface ///If an override exists for the browserExecutableFolder or the channel preference, the override is used. ///If an override is not specified, then the parameter value passed to [getAvailableVersion] is used. ///Returns `null` if it fails to find an installed WebView2 runtime or non-stable Microsoft Edge installation. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - GetAvailableCoreWebView2BrowserVersionString](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#comparebrowserversions)) ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getAvailableVersion.supported_platforms} + @SupportedPlatforms(platforms: [ + WindowsPlatform( + apiName: 'GetAvailableCoreWebView2BrowserVersionString', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#getavailablecorewebview2browserversionstring') + ]) Future getAvailableVersion({String? browserExecutableFolder}) { throw UnimplementedError( 'getAvailableVersion is not implemented on the current platform'); @@ -122,21 +221,137 @@ abstract class PlatformWebViewEnvironment extends PlatformInterface ///Sets the value of result to `-1`, `0` or `1` if version1 is less than, equal or greater than version2 respectively. ///Returns `null` if it fails to parse any of the version strings. ///Directly use the version info obtained from [getAvailableVersion] with input, channel information is ignored. - /// - ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - CompareBrowserVersions](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#comparebrowserversions)) ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.compareBrowserVersions.supported_platforms} + @SupportedPlatforms(platforms: [ + WindowsPlatform( + apiName: 'CompareBrowserVersions', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#comparebrowserversions') + ]) Future compareBrowserVersions( {required String version1, required String version2}) { throw UnimplementedError( 'compareBrowserVersions is not implemented on the current platform'); } + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.onNewBrowserVersionAvailable} + ///[onNewBrowserVersionAvailable] runs when a newer version of the WebView2 Runtime + ///is installed and available using WebView2. + ///To use the newer version of the browser you must create a new [PlatformWebViewEnvironment] and WebView. + ///The event only runs for new version from the same WebView2 Runtime from which the code is running. + ///When not running with installed WebView2 Runtime, no event is run. + /// + ///Because a user data folder is only able to be used by one browser process at a time, + ///if you want to use the same user data folder in the WebView using the new version of the browser, + ///you must close the environment and instance of WebView that are using the older version of the browser first. + ///Or simply prompt the user to restart the app. + ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.onNewBrowserVersionAvailable.supported_platforms} + @SupportedPlatforms(platforms: [ + WindowsPlatform( + apiName: 'ICoreWebView2Environment.add_NewBrowserVersionAvailable', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environment?view=webview2-1.0.2849.39#add_newbrowserversionavailable') + ]) + void Function()? onNewBrowserVersionAvailable; + + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.onBrowserProcessExited} + ///The [onBrowserProcessExited] event is raised when the collection of WebView2 Runtime + ///processes for the browser process of this environment terminate due to browser process failure + ///or normal shutdown (for example, when all associated WebViews are closed), + ///after all resources have been released (including the user data folder). + ///To learn about what these processes are, go to [Process model](https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/process-model). + /// + ///Multiple app processes can share a browser process by creating their webviews + ///from a [PlatformWebViewEnvironment] with the same user data folder. + ///When the entire collection of WebView2Runtime processes for the browser process exit, + ///all associated [PlatformWebViewEnvironment] objects receive the [onBrowserProcessExited] event. + ///Multiple processes sharing the same browser process need to coordinate their + ///use of the shared user data folder to avoid race conditions and unnecessary waits. + ///For example, one process should not clear the user data folder at the same + ///time that another process recovers from a crash by recreating its WebView controls; + ///one process should not block waiting for the event if other app processes + ///are using the same browser process (the browser process will not exit + ///until those other processes have closed their webviews too). + /// + ///The difference between [onBrowserProcessExited] and [PlatformWebViewCreationParams.onProcessFailed] is that + ///[onBrowserProcessExited] is raised for any browser process exit + ///(expected or unexpected, after all associated processes have exited too), + ///while [PlatformWebViewCreationParams.onProcessFailed] is raised for + ///unexpected process exits of any kind (browser, render, GPU, and all other types), + ///or for main frame render process unresponsiveness. + ///To learn more about the WebView2 Process Model, go to + ///[Process model](https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/process-model). + /// + ///In the case the browser process crashes, both [onBrowserProcessExited] and + ///[PlatformWebViewCreationParams.onProcessFailed] events are raised, but the order is not guaranteed. + ///These events are intended for different scenarios. + ///It is up to the app to coordinate the handlers so they do not try to perform + ///reliability recovery while also trying to move to a new WebView2 Runtime version + ///or remove the user data folder. + ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.onBrowserProcessExited.supported_platforms} + @SupportedPlatforms(platforms: [ + WindowsPlatform( + available: '1.0.992.28+', + apiName: 'ICoreWebView2Environment5.add_BrowserProcessExited', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environment5?view=webview2-1.0.2849.39#add_browserprocessexited') + ]) + void Function(BrowserProcessExitedDetail detail)? onBrowserProcessExited; + + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.onProcessInfosChanged} + ///Event fired with a list of all process using same user data folder except for crashpad process. + ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.onProcessInfosChanged.supported_platforms} + @SupportedPlatforms(platforms: [ + WindowsPlatform( + available: '1.0.1108.44+', + apiName: 'ICoreWebView2Environment8.add_ProcessInfosChanged', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environment8?view=webview2-1.0.2849.39#add_processinfoschanged') + ]) + void Function(BrowserProcessInfosChangedDetail detail)? onProcessInfosChanged; + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.dispose} ///Disposes the WebView Environment reference. ///{@endtemplate} + /// + ///{@macro flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.dispose.supported_platforms} + @SupportedPlatforms(platforms: [WindowsPlatform()]) Future dispose() { throw UnimplementedError( 'dispose is not implemented on the current platform'); } + + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.isClassSupported} + ///Check if the current class is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isClassSupported({TargetPlatform? platform}) => + _PlatformWebViewEnvironmentClassSupported.isClassSupported( + platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.isPropertySupported} + ///Check if the given [property] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///The property should be one of the [PlatformWebViewEnvironmentProperty] or [PlatformWebViewEnvironmentCreationParamsProperty] values. + ///{@endtemplate} + bool isPropertySupported(dynamic property, {TargetPlatform? platform}) => + property is PlatformWebViewEnvironmentCreationParamsProperty + ? params.isPropertySupported(property, platform: platform) + : _PlatformWebViewEnvironmentPropertySupported.isPropertySupported( + property, + platform: platform); + + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.isMethodSupported} + ///Check if the given [method] is supported by the [defaultTargetPlatform] or a specific [platform]. + ///{@endtemplate} + bool isMethodSupported(PlatformWebViewEnvironmentMethod method, + {TargetPlatform? platform}) => + _PlatformWebViewEnvironmentMethodSupported.isMethodSupported(method, + platform: platform); } diff --git a/flutter_inappwebview_platform_interface/lib/src/webview_environment/platform_webview_environment.g.dart b/flutter_inappwebview_platform_interface/lib/src/webview_environment/platform_webview_environment.g.dart new file mode 100644 index 000000000..3ad81f5a0 --- /dev/null +++ b/flutter_inappwebview_platform_interface/lib/src/webview_environment/platform_webview_environment.g.dart @@ -0,0 +1,273 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'platform_webview_environment.dart'; + +// ************************************************************************** +// SupportedPlatformsGenerator +// ************************************************************************** + +extension _PlatformWebViewEnvironmentCreationParamsClassSupported + on PlatformWebViewEnvironmentCreationParams { + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironmentCreationParams.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 + /// + ///Use the [PlatformWebViewEnvironmentCreationParams.isClassSupported] method to check if this class is supported at runtime. + ///{@endtemplate} + static bool isClassSupported({TargetPlatform? platform}) { + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.windows].contains(platform ?? defaultTargetPlatform); + } +} + +///List of [PlatformWebViewEnvironmentCreationParams]'s properties that can be used to check i they are supported or not by the current platform. +enum PlatformWebViewEnvironmentCreationParamsProperty { + ///Can be used to check if the [PlatformWebViewEnvironmentCreationParams.settings] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironmentCreationParams.settings.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 + /// + ///Use the [PlatformWebViewEnvironmentCreationParams.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + settings, +} + +extension _PlatformWebViewEnvironmentCreationParamsPropertySupported + on PlatformWebViewEnvironmentCreationParams { + static bool isPropertySupported( + PlatformWebViewEnvironmentCreationParamsProperty property, + {TargetPlatform? platform}) { + switch (property) { + case PlatformWebViewEnvironmentCreationParamsProperty.settings: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.windows] + .contains(platform ?? defaultTargetPlatform); + } + } +} + +extension _PlatformWebViewEnvironmentClassSupported + on PlatformWebViewEnvironment { + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 + /// + ///Use the [PlatformWebViewEnvironment.isClassSupported] method to check if this class is supported at runtime. + ///{@endtemplate} + static bool isClassSupported({TargetPlatform? platform}) { + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.windows].contains(platform ?? defaultTargetPlatform); + } +} + +///List of [PlatformWebViewEnvironment]'s properties that can be used to check i they are supported or not by the current platform. +enum PlatformWebViewEnvironmentProperty { + ///Can be used to check if the [PlatformWebViewEnvironment.id] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.id.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 + /// + ///Use the [PlatformWebViewEnvironment.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + id, + + ///Can be used to check if the [PlatformWebViewEnvironment.onBrowserProcessExited] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.onBrowserProcessExited.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 1.0.992.28++ ([Official API - ICoreWebView2Environment5.add_BrowserProcessExited](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environment5?view=webview2-1.0.2849.39#add_browserprocessexited)) + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [detail]: all platforms + /// + ///Use the [PlatformWebViewEnvironment.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + onBrowserProcessExited, + + ///Can be used to check if the [PlatformWebViewEnvironment.onNewBrowserVersionAvailable] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.onNewBrowserVersionAvailable.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - ICoreWebView2Environment.add_NewBrowserVersionAvailable](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environment?view=webview2-1.0.2849.39#add_newbrowserversionavailable)) + /// + ///Use the [PlatformWebViewEnvironment.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + onNewBrowserVersionAvailable, + + ///Can be used to check if the [PlatformWebViewEnvironment.onProcessInfosChanged] property is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.onProcessInfosChanged.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 1.0.1108.44++ ([Official API - ICoreWebView2Environment8.add_ProcessInfosChanged](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environment8?view=webview2-1.0.2849.39#add_processinfoschanged)) + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [detail]: all platforms + /// + ///Use the [PlatformWebViewEnvironment.isPropertySupported] method to check if this property is supported at runtime. + ///{@endtemplate} + onProcessInfosChanged, +} + +extension _PlatformWebViewEnvironmentPropertySupported + on PlatformWebViewEnvironment { + static bool isPropertySupported(PlatformWebViewEnvironmentProperty property, + {TargetPlatform? platform}) { + switch (property) { + case PlatformWebViewEnvironmentProperty.id: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.windows] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebViewEnvironmentProperty.onBrowserProcessExited: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.windows] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebViewEnvironmentProperty.onNewBrowserVersionAvailable: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.windows] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebViewEnvironmentProperty.onProcessInfosChanged: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.windows] + .contains(platform ?? defaultTargetPlatform); + } + } +} + +///List of [PlatformWebViewEnvironment]'s methods that can be used to check if they are supported or not by the current platform. +enum PlatformWebViewEnvironmentMethod { + ///Can be used to check if the [PlatformWebViewEnvironment.compareBrowserVersions] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.compareBrowserVersions.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - CompareBrowserVersions](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#comparebrowserversions)) + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [version1]: all platforms + ///- [version2]: all platforms + /// + ///Use the [PlatformWebViewEnvironment.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + compareBrowserVersions, + + ///Can be used to check if the [PlatformWebViewEnvironment.create] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.create.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - CreateCoreWebView2EnvironmentWithOptions](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#createcorewebview2environmentwithoptions)) + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [settings]: all platforms + /// + ///Use the [PlatformWebViewEnvironment.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + create, + + ///Can be used to check if the [PlatformWebViewEnvironment.dispose] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.dispose.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 + /// + ///Use the [PlatformWebViewEnvironment.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + dispose, + + ///Can be used to check if the [PlatformWebViewEnvironment.getAvailableVersion] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getAvailableVersion.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 ([Official API - GetAvailableCoreWebView2BrowserVersionString](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2849.39#getavailablecorewebview2browserversionstring)) + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [browserExecutableFolder]: all platforms + /// + ///Use the [PlatformWebViewEnvironment.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + getAvailableVersion, + + ///Can be used to check if the [PlatformWebViewEnvironment.getFailureReportFolderPath] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getFailureReportFolderPath.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 1.0.1518.46++ ([Official API - ICoreWebView2Environment11.get_FailureReportFolderPath](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environment11?view=webview2-1.0.2849.39#get_failurereportfolderpath)) + /// + ///Use the [PlatformWebViewEnvironment.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + getFailureReportFolderPath, + + ///Can be used to check if the [PlatformWebViewEnvironment.getProcessInfos] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.getProcessInfos.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 1.0.1108.44++ ([Official API - ICoreWebView2Environment8.GetProcessInfos](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environment8?view=webview2-1.0.2849.39#getprocessinfos)) + /// + ///Use the [PlatformWebViewEnvironment.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + getProcessInfos, + + ///Can be used to check if the [PlatformWebViewEnvironment.isInterfaceSupported] method is supported at runtime. + /// + ///{@template flutter_inappwebview_platform_interface.PlatformWebViewEnvironment.isInterfaceSupported.supported_platforms} + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 + /// + ///**Parameters - Officially Supported Platforms/Implementations**: + ///- [interface]: all platforms + /// + ///Use the [PlatformWebViewEnvironment.isMethodSupported] method to check if this method is supported at runtime. + ///{@endtemplate} + isInterfaceSupported, +} + +extension _PlatformWebViewEnvironmentMethodSupported + on PlatformWebViewEnvironment { + static bool isMethodSupported(PlatformWebViewEnvironmentMethod method, + {TargetPlatform? platform}) { + switch (method) { + case PlatformWebViewEnvironmentMethod.compareBrowserVersions: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.windows] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebViewEnvironmentMethod.create: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.windows] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebViewEnvironmentMethod.dispose: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.windows] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebViewEnvironmentMethod.getAvailableVersion: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.windows] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebViewEnvironmentMethod.getFailureReportFolderPath: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.windows] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebViewEnvironmentMethod.getProcessInfos: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.windows] + .contains(platform ?? defaultTargetPlatform); + case PlatformWebViewEnvironmentMethod.isInterfaceSupported: + return ((kIsWeb && platform != null) || !kIsWeb) && + [TargetPlatform.windows] + .contains(platform ?? defaultTargetPlatform); + } + } +} diff --git a/flutter_inappwebview_platform_interface/lib/src/webview_environment/webview_environment_settings.dart b/flutter_inappwebview_platform_interface/lib/src/webview_environment/webview_environment_settings.dart index 244cdeeb9..c208d8781 100644 --- a/flutter_inappwebview_platform_interface/lib/src/webview_environment/webview_environment_settings.dart +++ b/flutter_inappwebview_platform_interface/lib/src/webview_environment/webview_environment_settings.dart @@ -2,6 +2,10 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_i import 'platform_webview_environment.dart'; import '../types/custom_scheme_registration.dart'; +import '../types/enum_method.dart'; +import '../types/environment_channel_search_kind.dart'; +import '../types/environment_release_channels.dart'; +import '../types/environment_scrollbar_style.dart'; part 'webview_environment_settings.g.dart'; @@ -104,19 +108,179 @@ class WebViewEnvironmentSettings_ { ///Set the array of custom scheme registrations to be used. @SupportedPlatforms(platforms: [ WindowsPlatform( + available: '1.0.1587.40', apiName: - 'ICoreWebView2EnvironmentOptions4.SetCustomSchemeRegistrations', + 'ICoreWebView2EnvironmentOptions4.SetCustomSchemeRegistrations', apiUrl: - 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions4?view=webview2-1.0.2739.15#setcustomschemeregistrations') + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions4?view=webview2-1.0.2739.15#setcustomschemeregistrations') ]) final List? customSchemeRegistrations; - WebViewEnvironmentSettings_( - {this.browserExecutableFolder, - this.userDataFolder, - this.additionalBrowserArguments, - this.allowSingleSignOnUsingOSPrimaryAccount, - this.language, - this.targetCompatibleBrowserVersion, - this.customSchemeRegistrations}); + ///Whether other processes can create WebView2 from WebView2Environment created + ///with the same user data folder and therefore sharing the same WebView browser process instance. + /// + ///The default value is `false`. + @SupportedPlatforms(platforms: [ + WindowsPlatform( + available: '1.0.1185.39', + apiName: + 'ICoreWebView2EnvironmentOptions2.put_ExclusiveUserDataFolderAccess', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions2?view=webview2-1.0.2849.39#put_exclusiveuserdatafolderaccess') + ]) + final bool? exclusiveUserDataFolderAccess; + + ///When IsCustomCrashReportingEnabled is set to `true`, + ///Windows won't send crash data to Microsoft endpoint. + /// + ///The default value is `false`. + ///In this case, WebView will respect OS consent. + @SupportedPlatforms(platforms: [ + WindowsPlatform( + available: '1.0.1518.46', + apiName: + 'ICoreWebView2EnvironmentOptions3.put_IsCustomCrashReportingEnabled', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions3?view=webview2-1.0.2849.39#put_iscustomcrashreportingenabled') + ]) + final bool? isCustomCrashReportingEnabled; + + ///This property is used to enable/disable tracking prevention feature in WebView2. + /// + ///This property enable/disable tracking prevention for all the WebView2's created in the same environment. + ///By default this feature is enabled to block potentially harmful trackers and trackers from sites that aren't visited before. + /// + ///You can set this property to `false` to disable the tracking prevention feature if the app + ///only renders content in the WebView2 that is known to be safe. + ///Disabling this feature when creating environment also improves runtime performance by skipping related code. + /// + ///You shouldn't disable this property if WebView2 is being used as a "full browser" + ///with arbitrary navigation and should protect end user privacy. + /// + ///Tracking prevention protects users from online tracking by restricting the ability + ///of trackers to access browser-based storage as well as the network. + ///See [Tracking prevention](https://learn.microsoft.com/en-us/microsoft-edge/web-platform/tracking-prevention). + @SupportedPlatforms(platforms: [ + WindowsPlatform( + available: '1.0.1661.34', + apiName: + 'ICoreWebView2EnvironmentOptions5.put_EnableTrackingPrevention', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions5?view=webview2-1.0.2849.39#put_enabletrackingprevention') + ]) + final bool? enableTrackingPrevention; + + ///When this property is set to `true` new extensions can be added to user profile and used. + /// + ///[areBrowserExtensionsEnabled] is default to be `false`, in this case, new extensions can't be installed, + ///and already installed extension won't be available to use in user profile. + ///If connecting to an already running environment with a different value for + ///[areBrowserExtensionsEnabled] property, it will fail with `HRESULT_FROM_WIN32(ERROR_INVALID_STATE)`. + @SupportedPlatforms(platforms: [ + WindowsPlatform( + available: '1.0.2210.55', + apiName: + 'ICoreWebView2EnvironmentOptions6.put_AreBrowserExtensionsEnabled', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions6?view=webview2-1.0.2849.39#put_arebrowserextensionsenabled') + ]) + final bool? areBrowserExtensionsEnabled; + + ///This property is [EnvironmentChannelSearchKind.MOST_STABLE] by default; + ///environment creation searches for a release channel on the machine from + ///most to least stable using the first channel found. + /// + ///The default search order is: WebView2 Runtime -> Beta -> Dev -> Canary. + ///Set [channelSearchKind] to [EnvironmentChannelSearchKind.LEAST_STABLE] to reverse + ///the search order so that environment creation searches for a channel from least to most stable. + ///If [releaseChannels] has been provided, the loader will only search for channels in the set. + ///See [EnvironmentReleaseChannels] for more details on channels. + /// + ///This property can be overridden by the corresponding registry key [channelSearchKind] + ///or the environment variable `WEBVIEW2_CHANNEL_SEARCH_KIND`. + ///Set the value to `1` to set the search kind to [EnvironmentChannelSearchKind.LEAST_STABLE]. + @SupportedPlatforms(platforms: [ + WindowsPlatform( + available: '1.0.2478.35', + apiName: 'ICoreWebView2EnvironmentOptions7.put_ChannelSearchKind', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions7?view=webview2-1.0.2849.39#put_channelsearchkind') + ]) + final EnvironmentChannelSearchKind_? channelSearchKind; + + ///Sets the [releaseChannels], which is a mask of one or more [EnvironmentReleaseChannels] + ///indicating which channels environment creation should search for. + /// + ///OR operation(s) can be applied to multiple [EnvironmentReleaseChannels] to create a mask. + ///The default value is a a mask of all the channels. + ///By default, environment creation searches for channels from most to least stable, + ///using the first channel found on the device. + ///When [releaseChannels] is provided, environment creation will only + ///search for the channels specified in the set. + ///Set [channelSearchKind] to [EnvironmentChannelSearchKind.LEAST_STABLE] to reverse + ///the search order so environment creation searches for least stable build first. + ///See [EnvironmentReleaseChannels] for descriptions of each channel. + /// + ///The [PlatformWebViewEnvironment] creation will fails with `HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)` + ///if environment creation is unable to find any channel from the EnvironmentReleaseChannels installed on the device. + ///Use [PlatformWebViewEnvironment.getAvailableVersion] to verify which channel is used when this option is set. + /// + ///Examples: + /// + ///| ReleaseChannels | Channel Search Kind: Most Stable (default) | Channel Search Kind: Least Stable | + ///|--------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------|--------------------------------------------| + ///| [EnvironmentReleaseChannels.BETA] | [EnvironmentReleaseChannels.STABLE] | WebView2 Runtime -> Beta | Beta -> WebView2 Runtime | + ///| [EnvironmentReleaseChannels.CANARY] | [EnvironmentReleaseChannels.DEV] | [EnvironmentReleaseChannels.BETA] | [EnvironmentReleaseChannels.STABLE] | WebView2 Runtime -> Beta -> Dev -> Canary | Canary -> Dev -> Beta -> WebView2 Runtime | + ///| [EnvironmentReleaseChannels.CANARY] | Canary | Canary | + ///| [EnvironmentReleaseChannels.BETA] | [EnvironmentReleaseChannels.CANARY] | [EnvironmentReleaseChannels.STABLE] | WebView2 Runtime -> Beta -> Canary | Canary -> Beta -> WebView2 Runtime | + /// + ///If both [browserExecutableFolder] and [releaseChannels] are provided, the [browserExecutableFolder] takes precedence, + ///regardless of whether or not the channel of [browserExecutableFolder] is included in the [releaseChannels]. + ///[releaseChannels] can be overridden by the corresponding registry override EnvironmentReleaseChannels or the environment + ///variable `WEBVIEW2_RELEASE_CHANNELS`. Set the value to a comma-separated string of integers, which map to + ///the following release channel values: Stable (0), Beta (1), Dev (2), and Canary (3). + ///For example, the values "0,2" and "2,0" indicate that environment creation should only search for + ///Dev channel and the WebView2 Runtime, using the order indicated by [channelSearchKind]. + ///[PlatformWebViewEnvironment] creation attempts to interpret each integer and treats any invalid entry as Stable channel. + @SupportedPlatforms(platforms: [ + WindowsPlatform( + available: '1.0.2478.35', + apiName: 'ICoreWebView2EnvironmentOptions7.put_ReleaseChannels', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions7?view=webview2-1.0.2849.39#put_releasechannels') + ]) + final EnvironmentReleaseChannels_? releaseChannels; + + ///The ScrollBar style being set on the WebView2 Environment. + /// + ///The default value is [EnvironmentScrollbarStyle.DEFAULT] which specifies the default browser ScrollBar style. + ///The `color-scheme` CSS property needs to be set on the corresponding + ///page to allow ScrollBar to follow light or dark theme. + ///Please see [color-scheme](https://developer.mozilla.org/docs/Web/CSS/color-scheme#declaring_color_scheme_preferences) for how `color-scheme` can be set. + ///CSS styles that modify the ScrollBar applied on top of native ScrollBar styling that is selected with [scrollbarStyle]. + @SupportedPlatforms(platforms: [ + WindowsPlatform( + available: '1.0.2535.41', + apiName: 'ICoreWebView2EnvironmentOptions8.put_ScrollBarStyle', + apiUrl: + 'https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions8?view=webview2-1.0.2849.39#put_scrollbarstyle') + ]) + final EnvironmentScrollbarStyle_? scrollbarStyle; + + WebViewEnvironmentSettings_({ + this.browserExecutableFolder, + this.userDataFolder, + this.additionalBrowserArguments, + this.allowSingleSignOnUsingOSPrimaryAccount, + this.language, + this.targetCompatibleBrowserVersion, + this.customSchemeRegistrations, + this.exclusiveUserDataFolderAccess, + this.isCustomCrashReportingEnabled, + this.enableTrackingPrevention, + this.areBrowserExtensionsEnabled, + this.channelSearchKind, + this.releaseChannels, + this.scrollbarStyle, + }); } diff --git a/flutter_inappwebview_platform_interface/lib/src/webview_environment/webview_environment_settings.g.dart b/flutter_inappwebview_platform_interface/lib/src/webview_environment/webview_environment_settings.g.dart index 322058d8b..0f84d0c5f 100644 --- a/flutter_inappwebview_platform_interface/lib/src/webview_environment/webview_environment_settings.g.dart +++ b/flutter_inappwebview_platform_interface/lib/src/webview_environment/webview_environment_settings.g.dart @@ -12,7 +12,7 @@ part of 'webview_environment_settings.dart'; ///may be overridden by values either specified in environment variables or in the registry. /// ///**Officially Supported Platforms/Implementations**: -///- Windows +///- Windows WebView2 class WebViewEnvironmentSettings { ///If there are multiple switches, there should be a space in between them. ///The one exception is if multiple features are being enabled/disabled for a single switch, @@ -20,16 +20,27 @@ class WebViewEnvironmentSettings { ///Example: `"--disable-features=feature1,feature2 --some-other-switch --do-something"` /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - ICoreWebView2EnvironmentOptions.put_AdditionalBrowserArguments](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions?view=webview2-1.0.2210.55#put_additionalbrowserarguments)) + ///- Windows WebView2 ([Official API - ICoreWebView2EnvironmentOptions.put_AdditionalBrowserArguments](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions?view=webview2-1.0.2210.55#put_additionalbrowserarguments)) final String? additionalBrowserArguments; ///This property is used to enable single sign on with Azure Active Directory (AAD) ///and personal Microsoft Account (MSA) resources inside WebView. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - ICoreWebView2EnvironmentOptions.put_AllowSingleSignOnUsingOSPrimaryAccount](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions?view=webview2-1.0.2210.55#put_allowsinglesignonusingosprimaryaccount)) + ///- Windows WebView2 ([Official API - ICoreWebView2EnvironmentOptions.put_AllowSingleSignOnUsingOSPrimaryAccount](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions?view=webview2-1.0.2210.55#put_allowsinglesignonusingosprimaryaccount)) final bool? allowSingleSignOnUsingOSPrimaryAccount; + ///When this property is set to `true` new extensions can be added to user profile and used. + /// + ///[areBrowserExtensionsEnabled] is default to be `false`, in this case, new extensions can't be installed, + ///and already installed extension won't be available to use in user profile. + ///If connecting to an already running environment with a different value for + ///[areBrowserExtensionsEnabled] property, it will fail with `HRESULT_FROM_WIN32(ERROR_INVALID_STATE)`. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 1.0.2210.55+ ([Official API - ICoreWebView2EnvironmentOptions6.put_AreBrowserExtensionsEnabled](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions6?view=webview2-1.0.2849.39#put_arebrowserextensionsenabled)) + final bool? areBrowserExtensionsEnabled; + ///Use [browserExecutableFolder] to specify whether WebView2 controls use a fixed ///or installed version of the WebView2 Runtime that exists on a user machine. ///To use a fixed version of the WebView2 Runtime, pass the folder path that contains @@ -47,25 +58,133 @@ class WebViewEnvironmentSettings { ///applicable `releaseChannelPreference` registry value is set to `1`, the channel search order is reversed. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - CreateCoreWebView2EnvironmentWithOptions.browserExecutableFolder](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#createcorewebview2environmentwithoptions)) + ///- Windows WebView2 ([Official API - CreateCoreWebView2EnvironmentWithOptions.browserExecutableFolder](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#createcorewebview2environmentwithoptions)) final String? browserExecutableFolder; + ///This property is [EnvironmentChannelSearchKind.MOST_STABLE] by default; + ///environment creation searches for a release channel on the machine from + ///most to least stable using the first channel found. + /// + ///The default search order is: WebView2 Runtime -> Beta -> Dev -> Canary. + ///Set [channelSearchKind] to [EnvironmentChannelSearchKind.LEAST_STABLE] to reverse + ///the search order so that environment creation searches for a channel from least to most stable. + ///If [releaseChannels] has been provided, the loader will only search for channels in the set. + ///See [EnvironmentReleaseChannels] for more details on channels. + /// + ///This property can be overridden by the corresponding registry key [channelSearchKind] + ///or the environment variable `WEBVIEW2_CHANNEL_SEARCH_KIND`. + ///Set the value to `1` to set the search kind to [EnvironmentChannelSearchKind.LEAST_STABLE]. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 1.0.2478.35+ ([Official API - ICoreWebView2EnvironmentOptions7.put_ChannelSearchKind](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions7?view=webview2-1.0.2849.39#put_channelsearchkind)) + final EnvironmentChannelSearchKind? channelSearchKind; + ///Set the array of custom scheme registrations to be used. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - ICoreWebView2EnvironmentOptions4.SetCustomSchemeRegistrations](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions4?view=webview2-1.0.2739.15#setcustomschemeregistrations)) + ///- Windows WebView2 1.0.1587.40+ ([Official API - ICoreWebView2EnvironmentOptions4.SetCustomSchemeRegistrations](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions4?view=webview2-1.0.2739.15#setcustomschemeregistrations)) final List? customSchemeRegistrations; + ///This property is used to enable/disable tracking prevention feature in WebView2. + /// + ///This property enable/disable tracking prevention for all the WebView2's created in the same environment. + ///By default this feature is enabled to block potentially harmful trackers and trackers from sites that aren't visited before. + /// + ///You can set this property to `false` to disable the tracking prevention feature if the app + ///only renders content in the WebView2 that is known to be safe. + ///Disabling this feature when creating environment also improves runtime performance by skipping related code. + /// + ///You shouldn't disable this property if WebView2 is being used as a "full browser" + ///with arbitrary navigation and should protect end user privacy. + /// + ///Tracking prevention protects users from online tracking by restricting the ability + ///of trackers to access browser-based storage as well as the network. + ///See [Tracking prevention](https://learn.microsoft.com/en-us/microsoft-edge/web-platform/tracking-prevention). + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 1.0.1661.34+ ([Official API - ICoreWebView2EnvironmentOptions5.put_EnableTrackingPrevention](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions5?view=webview2-1.0.2849.39#put_enabletrackingprevention)) + final bool? enableTrackingPrevention; + + ///Whether other processes can create WebView2 from WebView2Environment created + ///with the same user data folder and therefore sharing the same WebView browser process instance. + /// + ///The default value is `false`. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 1.0.1185.39+ ([Official API - ICoreWebView2EnvironmentOptions2.put_ExclusiveUserDataFolderAccess](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions2?view=webview2-1.0.2849.39#put_exclusiveuserdatafolderaccess)) + final bool? exclusiveUserDataFolderAccess; + + ///When IsCustomCrashReportingEnabled is set to `true`, + ///Windows won't send crash data to Microsoft endpoint. + /// + ///The default value is `false`. + ///In this case, WebView will respect OS consent. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 1.0.1518.46+ ([Official API - ICoreWebView2EnvironmentOptions3.put_IsCustomCrashReportingEnabled](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions3?view=webview2-1.0.2849.39#put_iscustomcrashreportingenabled)) + final bool? isCustomCrashReportingEnabled; + ///The default display language for WebView. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - ICoreWebView2EnvironmentOptions.put_Language](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions?view=webview2-1.0.2210.55#put_language)) + ///- Windows WebView2 ([Official API - ICoreWebView2EnvironmentOptions.put_Language](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions?view=webview2-1.0.2210.55#put_language)) final String? language; + ///Sets the [releaseChannels], which is a mask of one or more [EnvironmentReleaseChannels] + ///indicating which channels environment creation should search for. + /// + ///OR operation(s) can be applied to multiple [EnvironmentReleaseChannels] to create a mask. + ///The default value is a a mask of all the channels. + ///By default, environment creation searches for channels from most to least stable, + ///using the first channel found on the device. + ///When [releaseChannels] is provided, environment creation will only + ///search for the channels specified in the set. + ///Set [channelSearchKind] to [EnvironmentChannelSearchKind.LEAST_STABLE] to reverse + ///the search order so environment creation searches for least stable build first. + ///See [EnvironmentReleaseChannels] for descriptions of each channel. + /// + ///The [PlatformWebViewEnvironment] creation will fails with `HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)` + ///if environment creation is unable to find any channel from the EnvironmentReleaseChannels installed on the device. + ///Use [PlatformWebViewEnvironment.getAvailableVersion] to verify which channel is used when this option is set. + /// + ///Examples: + /// + ///| ReleaseChannels | Channel Search Kind: Most Stable (default) | Channel Search Kind: Least Stable | + ///|--------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------|--------------------------------------------| + ///| [EnvironmentReleaseChannels.BETA] | [EnvironmentReleaseChannels.STABLE] | WebView2 Runtime -> Beta | Beta -> WebView2 Runtime | + ///| [EnvironmentReleaseChannels.CANARY] | [EnvironmentReleaseChannels.DEV] | [EnvironmentReleaseChannels.BETA] | [EnvironmentReleaseChannels.STABLE] | WebView2 Runtime -> Beta -> Dev -> Canary | Canary -> Dev -> Beta -> WebView2 Runtime | + ///| [EnvironmentReleaseChannels.CANARY] | Canary | Canary | + ///| [EnvironmentReleaseChannels.BETA] | [EnvironmentReleaseChannels.CANARY] | [EnvironmentReleaseChannels.STABLE] | WebView2 Runtime -> Beta -> Canary | Canary -> Beta -> WebView2 Runtime | + /// + ///If both [browserExecutableFolder] and [releaseChannels] are provided, the [browserExecutableFolder] takes precedence, + ///regardless of whether or not the channel of [browserExecutableFolder] is included in the [releaseChannels]. + ///[releaseChannels] can be overridden by the corresponding registry override EnvironmentReleaseChannels or the environment + ///variable `WEBVIEW2_RELEASE_CHANNELS`. Set the value to a comma-separated string of integers, which map to + ///the following release channel values: Stable (0), Beta (1), Dev (2), and Canary (3). + ///For example, the values "0,2" and "2,0" indicate that environment creation should only search for + ///Dev channel and the WebView2 Runtime, using the order indicated by [channelSearchKind]. + ///[PlatformWebViewEnvironment] creation attempts to interpret each integer and treats any invalid entry as Stable channel. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 1.0.2478.35+ ([Official API - ICoreWebView2EnvironmentOptions7.put_ReleaseChannels](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions7?view=webview2-1.0.2849.39#put_releasechannels)) + final EnvironmentReleaseChannels? releaseChannels; + + ///The ScrollBar style being set on the WebView2 Environment. + /// + ///The default value is [EnvironmentScrollbarStyle.DEFAULT] which specifies the default browser ScrollBar style. + ///The `color-scheme` CSS property needs to be set on the corresponding + ///page to allow ScrollBar to follow light or dark theme. + ///Please see [color-scheme](https://developer.mozilla.org/docs/Web/CSS/color-scheme#declaring_color_scheme_preferences) for how `color-scheme` can be set. + ///CSS styles that modify the ScrollBar applied on top of native ScrollBar styling that is selected with [scrollbarStyle]. + /// + ///**Officially Supported Platforms/Implementations**: + ///- Windows WebView2 1.0.2535.41+ ([Official API - ICoreWebView2EnvironmentOptions8.put_ScrollBarStyle](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions8?view=webview2-1.0.2849.39#put_scrollbarstyle)) + final EnvironmentScrollbarStyle? scrollbarStyle; + ///Specifies the version of the WebView2 Runtime binaries required to be compatible with your app. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - ICoreWebView2EnvironmentOptions.put_TargetCompatibleBrowserVersion](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions?view=webview2-1.0.2210.55#put_targetcompatiblebrowserversion)) + ///- Windows WebView2 ([Official API - ICoreWebView2EnvironmentOptions.put_TargetCompatibleBrowserVersion](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2environmentoptions?view=webview2-1.0.2210.55#put_targetcompatiblebrowserversion)) final String? targetCompatibleBrowserVersion; ///You may specify the [userDataFolder] to change the default user data folder location for WebView2. @@ -84,23 +203,31 @@ class WebViewEnvironmentSettings { ///running in the shared browser process. /// ///**Officially Supported Platforms/Implementations**: - ///- Windows ([Official API - CreateCoreWebView2EnvironmentWithOptions.userDataFolder](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#createcorewebview2environmentwithoptions)) + ///- Windows WebView2 ([Official API - CreateCoreWebView2EnvironmentWithOptions.userDataFolder](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?view=webview2-1.0.2210.55#createcorewebview2environmentwithoptions)) final String? userDataFolder; /// ///**Officially Supported Platforms/Implementations**: - ///- Windows + ///- Windows WebView2 WebViewEnvironmentSettings( {this.additionalBrowserArguments, this.allowSingleSignOnUsingOSPrimaryAccount, + this.areBrowserExtensionsEnabled, this.browserExecutableFolder, + this.channelSearchKind, this.customSchemeRegistrations, + this.enableTrackingPrevention, + this.exclusiveUserDataFolderAccess, + this.isCustomCrashReportingEnabled, this.language, + this.releaseChannels, + this.scrollbarStyle, this.targetCompatibleBrowserVersion, this.userDataFolder}); ///Gets a possible [WebViewEnvironmentSettings] instance from a [Map] value. - static WebViewEnvironmentSettings? fromMap(Map? map) { + static WebViewEnvironmentSettings? fromMap(Map? map, + {EnumMethod? enumMethod}) { if (map == null) { return null; } @@ -108,13 +235,42 @@ class WebViewEnvironmentSettings { additionalBrowserArguments: map['additionalBrowserArguments'], allowSingleSignOnUsingOSPrimaryAccount: map['allowSingleSignOnUsingOSPrimaryAccount'], + areBrowserExtensionsEnabled: map['areBrowserExtensionsEnabled'], browserExecutableFolder: map['browserExecutableFolder'], + channelSearchKind: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => EnvironmentChannelSearchKind.fromNativeValue( + map['channelSearchKind']), + EnumMethod.value => + EnvironmentChannelSearchKind.fromValue(map['channelSearchKind']), + EnumMethod.name => + EnvironmentChannelSearchKind.byName(map['channelSearchKind']) + }, customSchemeRegistrations: map['customSchemeRegistrations'] != null ? List.from(map['customSchemeRegistrations'] .map((e) => CustomSchemeRegistration.fromMap( - e?.cast())!)) + e?.cast(), + enumMethod: enumMethod)!)) : null, + enableTrackingPrevention: map['enableTrackingPrevention'], + exclusiveUserDataFolderAccess: map['exclusiveUserDataFolderAccess'], + isCustomCrashReportingEnabled: map['isCustomCrashReportingEnabled'], language: map['language'], + releaseChannels: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + EnvironmentReleaseChannels.fromNativeValue(map['releaseChannels']), + EnumMethod.value => + EnvironmentReleaseChannels.fromValue(map['releaseChannels']), + EnumMethod.name => + EnvironmentReleaseChannels.byName(map['releaseChannels']) + }, + scrollbarStyle: switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => + EnvironmentScrollbarStyle.fromNativeValue(map['scrollbarStyle']), + EnumMethod.value => + EnvironmentScrollbarStyle.fromValue(map['scrollbarStyle']), + EnumMethod.name => + EnvironmentScrollbarStyle.byName(map['scrollbarStyle']) + }, targetCompatibleBrowserVersion: map['targetCompatibleBrowserVersion'], userDataFolder: map['userDataFolder'], ); @@ -122,15 +278,35 @@ class WebViewEnvironmentSettings { } ///Converts instance to a map. - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "additionalBrowserArguments": additionalBrowserArguments, "allowSingleSignOnUsingOSPrimaryAccount": allowSingleSignOnUsingOSPrimaryAccount, + "areBrowserExtensionsEnabled": areBrowserExtensionsEnabled, "browserExecutableFolder": browserExecutableFolder, - "customSchemeRegistrations": - customSchemeRegistrations?.map((e) => e.toMap()).toList(), + "channelSearchKind": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => channelSearchKind?.toNativeValue(), + EnumMethod.value => channelSearchKind?.toValue(), + EnumMethod.name => channelSearchKind?.name() + }, + "customSchemeRegistrations": customSchemeRegistrations + ?.map((e) => e.toMap(enumMethod: enumMethod)) + .toList(), + "enableTrackingPrevention": enableTrackingPrevention, + "exclusiveUserDataFolderAccess": exclusiveUserDataFolderAccess, + "isCustomCrashReportingEnabled": isCustomCrashReportingEnabled, "language": language, + "releaseChannels": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => releaseChannels?.toNativeValue(), + EnumMethod.value => releaseChannels?.toValue(), + EnumMethod.name => releaseChannels?.name() + }, + "scrollbarStyle": switch (enumMethod ?? EnumMethod.nativeValue) { + EnumMethod.nativeValue => scrollbarStyle?.toNativeValue(), + EnumMethod.value => scrollbarStyle?.toValue(), + EnumMethod.name => scrollbarStyle?.name() + }, "targetCompatibleBrowserVersion": targetCompatibleBrowserVersion, "userDataFolder": userDataFolder, }; @@ -149,6 +325,6 @@ class WebViewEnvironmentSettings { @override String toString() { - return 'WebViewEnvironmentSettings{additionalBrowserArguments: $additionalBrowserArguments, allowSingleSignOnUsingOSPrimaryAccount: $allowSingleSignOnUsingOSPrimaryAccount, browserExecutableFolder: $browserExecutableFolder, customSchemeRegistrations: $customSchemeRegistrations, language: $language, targetCompatibleBrowserVersion: $targetCompatibleBrowserVersion, userDataFolder: $userDataFolder}'; + return 'WebViewEnvironmentSettings{additionalBrowserArguments: $additionalBrowserArguments, allowSingleSignOnUsingOSPrimaryAccount: $allowSingleSignOnUsingOSPrimaryAccount, areBrowserExtensionsEnabled: $areBrowserExtensionsEnabled, browserExecutableFolder: $browserExecutableFolder, channelSearchKind: $channelSearchKind, customSchemeRegistrations: $customSchemeRegistrations, enableTrackingPrevention: $enableTrackingPrevention, exclusiveUserDataFolderAccess: $exclusiveUserDataFolderAccess, isCustomCrashReportingEnabled: $isCustomCrashReportingEnabled, language: $language, releaseChannels: $releaseChannels, scrollbarStyle: $scrollbarStyle, targetCompatibleBrowserVersion: $targetCompatibleBrowserVersion, userDataFolder: $userDataFolder}'; } } diff --git a/flutter_inappwebview_platform_interface/lib/src/x509_certificate/x509_certificate.dart b/flutter_inappwebview_platform_interface/lib/src/x509_certificate/x509_certificate.dart index b0d3555f3..03d7d683a 100644 --- a/flutter_inappwebview_platform_interface/lib/src/x509_certificate/x509_certificate.dart +++ b/flutter_inappwebview_platform_interface/lib/src/x509_certificate/x509_certificate.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:typed_data'; +import '../types/enum_method.dart'; import 'asn1_decoder.dart'; import 'asn1_object.dart'; import 'oid.dart'; @@ -86,7 +87,7 @@ class X509Certificate { Uint8List? derDataDecoded; try { - derDataDecoded = Uint8List.fromList(utf8.encode(base64buffer)); + derDataDecoded = Uint8List.fromList(base64Decode(base64buffer)); } catch (e) {} if (derDataDecoded != null) { return derDataDecoded; @@ -402,9 +403,9 @@ class X509Certificate { return description; } - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "basicConstraints": basicConstraints?.toMap(), + "basicConstraints": basicConstraints?.toMap(enumMethod: enumMethod), "subjectAlternativeNames": subjectAlternativeNames, "issuerAlternativeNames": issuerAlternativeNames, "extendedKeyUsage": extendedKeyUsage, @@ -422,12 +423,15 @@ class X509Certificate { "criticalExtensionOIDs": criticalExtensionOIDs, "nonCriticalExtensionOIDs": nonCriticalExtensionOIDs, "encoded": encoded, - "publicKey": publicKey?.toMap(), - "subjectKeyIdentifier": subjectKeyIdentifier?.toMap(), - "authorityKeyIdentifier": authorityKeyIdentifier?.toMap(), - "certificatePolicies": certificatePolicies?.toMap(), - "cRLDistributionPoints": cRLDistributionPoints?.toMap(), - "authorityInfoAccess": authorityInfoAccess?.toMap(), + "publicKey": publicKey?.toMap(enumMethod: enumMethod), + "subjectKeyIdentifier": + subjectKeyIdentifier?.toMap(enumMethod: enumMethod), + "authorityKeyIdentifier": + authorityKeyIdentifier?.toMap(enumMethod: enumMethod), + "certificatePolicies": certificatePolicies?.toMap(enumMethod: enumMethod), + "cRLDistributionPoints": + cRLDistributionPoints?.toMap(enumMethod: enumMethod), + "authorityInfoAccess": authorityInfoAccess?.toMap(enumMethod: enumMethod), }; } diff --git a/flutter_inappwebview_platform_interface/lib/src/x509_certificate/x509_extension.dart b/flutter_inappwebview_platform_interface/lib/src/x509_certificate/x509_extension.dart index 8618dfde5..982b1e3c5 100644 --- a/flutter_inappwebview_platform_interface/lib/src/x509_certificate/x509_extension.dart +++ b/flutter_inappwebview_platform_interface/lib/src/x509_certificate/x509_extension.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import '../types/enum_method.dart'; import 'x509_certificate.dart'; import 'asn1_object.dart'; import 'oid.dart'; @@ -157,7 +158,7 @@ class BasicConstraintExtension extends X509Extension { return toMap().toString(); } - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "isCA": isCA, "pathLenConstraint": pathLenConstraint, @@ -187,7 +188,7 @@ class SubjectKeyIdentifierExtension extends X509Extension { return toMap().toString(); } - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "value": value, }; @@ -209,7 +210,7 @@ class AuthorityInfoAccess { return toMap().toString(); } - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "method": method, "location": location, @@ -251,9 +252,10 @@ class AuthorityInfoAccessExtension extends X509Extension { return toMap().toString(); } - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "infoAccess": infoAccess?.map((e) => e.toMap()).toList(), + "infoAccess": + infoAccess?.map((e) => e.toMap(enumMethod: enumMethod)).toList(), }; } @@ -327,7 +329,7 @@ class AuthorityKeyIdentifierExtension extends X509Extension { return toMap().toString(); } - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "keyIdentifier": keyIdentifier, "certificateIssuer": certificateIssuer, @@ -351,7 +353,7 @@ class CertificatePolicyQualifier { return toMap().toString(); } - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "oid": oid, "value": value, @@ -374,10 +376,11 @@ class CertificatePolicy { return toMap().toString(); } - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "oid": oid, - "qualifiers": qualifiers?.map((e) => e.toMap()).toList(), + "qualifiers": + qualifiers?.map((e) => e.toMap(enumMethod: enumMethod)).toList(), }; } @@ -436,9 +439,10 @@ class CertificatePoliciesExtension extends X509Extension { return toMap().toString(); } - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { - "policies": policies?.map((e) => e.toMap()).toList(), + "policies": + policies?.map((e) => e.toMap(enumMethod: enumMethod)).toList(), }; } @@ -470,7 +474,7 @@ class CRLDistributionPointsExtension extends X509Extension { return toMap().toString(); } - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "crls": crls, }; diff --git a/flutter_inappwebview_platform_interface/lib/src/x509_certificate/x509_public_key.dart b/flutter_inappwebview_platform_interface/lib/src/x509_certificate/x509_public_key.dart index c4661e906..30de5b05f 100644 --- a/flutter_inappwebview_platform_interface/lib/src/x509_certificate/x509_public_key.dart +++ b/flutter_inappwebview_platform_interface/lib/src/x509_certificate/x509_public_key.dart @@ -1,5 +1,6 @@ import 'dart:typed_data'; +import '../types/enum_method.dart'; import 'asn1_decoder.dart'; import 'asn1_der_encoder.dart'; import 'asn1_object.dart'; @@ -50,7 +51,7 @@ class X509PublicKey { return null; } - Map toMap() { + Map toMap({EnumMethod? enumMethod}) { return { "algOid": algOid, "algName": algName, diff --git a/flutter_inappwebview_platform_interface/pubspec.yaml b/flutter_inappwebview_platform_interface/pubspec.yaml index 16a58f358..f6dfa65db 100644 --- a/flutter_inappwebview_platform_interface/pubspec.yaml +++ b/flutter_inappwebview_platform_interface/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview_platform_interface description: A common platform interface for the flutter_inappwebview plugin. -version: 1.3.0+1 +version: 1.4.0-beta.3 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_platform_interface issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues @@ -20,7 +20,8 @@ environment: dependencies: flutter: sdk: flutter - flutter_inappwebview_internal_annotations: ^1.1.1 + flutter_inappwebview_internal_annotations: #^1.3.0 + path: ../dev_packages/flutter_inappwebview_internal_annotations plugin_platform_interface: ^2.1.8 dev_dependencies: diff --git a/flutter_inappwebview_web/CHANGELOG.md b/flutter_inappwebview_web/CHANGELOG.md index c02525fc0..60e8d1ce4 100644 --- a/flutter_inappwebview_web/CHANGELOG.md +++ b/flutter_inappwebview_web/CHANGELOG.md @@ -1,3 +1,23 @@ +## 1.2.0-beta.3 + +- Updated flutter_inappwebview_platform_interface version to ^1.4.0-beta.3 +- Updated `onCreateWindow` WebView event +- Implemented `onCloseWindow`, `onCallJsHandler` WebView events +- Implemented `addJavaScriptHandler`, `removeJavaScriptHandler`, `hasJavaScriptHandler`, `addUserScript`, `addUserScripts`, `removeUserScript`, `removeUserScriptsByGroupName`, `removeUserScripts`, `hasUserScript` InAppWebViewController methods +- Implemented `setJavaScriptBridgeName`, `getJavaScriptBridgeName`, `getDefaultUserAgent` InAppWebViewController static methods +- Implemented `javaScriptHandlersOriginAllowList`, `javaScriptBridgeEnabled`, `javaScriptBridgeOriginAllowList`, `hasJavaScriptHandler`, `addUserScript`, `addUserScripts`, `removeUserScript` InAppWebViewSettings event +- Merged "fix #2484, Remove not-empty assert for Cookie.value" [#2486](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2486) (thanks to [laishere](https://github.com/laishere)) + +## 1.2.0-beta.2 + +- Updated flutter_inappwebview_platform_interface version to ^1.4.0-beta.2 + +## 1.2.0-beta.1 + +- Updated flutter_inappwebview_platform_interface version to ^1.4.0-beta.1 +- Merged "[web] support iframe role and aria-hidden attributes" [2293](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2293) (thanks to [p-mazhnik](https://github.com/p-mazhnik)) +- Fixed 'Type 'int' is not a subtype of type 'JSValue' in type cast' when compiling/running using WASM + ## 1.1.2 - Updated flutter_inappwebview_platform_interface version to ^1.3.0 diff --git a/flutter_inappwebview_web/example/pubspec.lock b/flutter_inappwebview_web/example/pubspec.lock index e6765a52a..f8412387b 100644 --- a/flutter_inappwebview_web/example/pubspec.lock +++ b/flutter_inappwebview_web/example/pubspec.lock @@ -79,25 +79,24 @@ packages: dependency: transitive description: name: flutter_inappwebview_internal_annotations - sha256: "5f80fd30e208ddded7dbbcd0d569e7995f9f63d45ea3f548d8dd4c0b473fb4c8" + sha256: "787171d43f8af67864740b6f04166c13190aa74a1468a1f1f1e9ee5b90c359cd" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" flutter_inappwebview_platform_interface: dependency: transitive description: - name: flutter_inappwebview_platform_interface - sha256: "6862f4e08aa8f6136762e022c9c1edafb18c1dc3beb03052f2f3f2a48605a182" - url: "https://pub.dev" - source: hosted - version: "1.3.0" + path: "../../flutter_inappwebview_platform_interface" + relative: true + source: path + version: "1.4.0-beta.3" flutter_inappwebview_web: dependency: "direct main" description: path: ".." relative: true source: path - version: "1.1.2" + version: "1.2.0-beta.3" flutter_lints: dependency: "direct dev" description: diff --git a/flutter_inappwebview_web/lib/assets/web/web_support.js b/flutter_inappwebview_web/lib/assets/web/web_support.js index e3893d874..fe9282c0f 100644 --- a/flutter_inappwebview_web/lib/assets/web/web_support.js +++ b/flutter_inappwebview_web/lib/assets/web/web_support.js @@ -1,593 +1,691 @@ -window.flutter_inappwebview = { - webViews: {}, - /** - * @param viewId {number | string} - * @param iframe {HTMLIFrameElement} - * @param iframeContainer {HTMLDivElement} - */ - createFlutterInAppWebView: function(viewId, iframe, iframeContainer) { - const iframeId = iframe.id; - var webView = { - viewId: viewId, - iframeId: iframeId, - iframe: null, - iframeContainer: null, - windowAutoincrementId: 0, - windows: {}, - isFullscreen: false, - documentTitle: null, - functionMap: {}, - settings: {}, - disableContextMenuHandler: function(event) { - event.preventDefault(); - event.stopPropagation(); - return false; - }, - prepare: function(settings) { - webView.settings = settings; - - document.addEventListener('fullscreenchange', function(event) { - // document.fullscreenElement will point to the element that - // is in fullscreen mode if there is one. If there isn't one, - // the value of the property is null. - if (document.fullscreenElement && document.fullscreenElement.id == iframeId) { - webView.isFullscreen = true; - window.flutter_inappwebview.nativeCommunication('onEnterFullscreen', viewId); - } else if (!document.fullscreenElement && webView.isFullscreen) { - webView.isFullscreen = false; - window.flutter_inappwebview.nativeCommunication('onExitFullscreen', viewId); - } else { - webView.isFullscreen = false; - } - }); - - if (iframe != null) { - webView.iframe = iframe; - webView.iframeContainer = iframeContainer; - iframe.addEventListener('load', function (event) { - webView.windowAutoincrementId = 0; - webView.windows = {}; - - var url = iframe.src; - try { - url = iframe.contentWindow.location.href; - } catch (e) { - console.log(e); - } - window.flutter_inappwebview.nativeCommunication('onLoadStart', viewId, [url]); - - try { - var oldLogs = { - 'log': iframe.contentWindow.console.log, - 'debug': iframe.contentWindow.console.debug, - 'error': iframe.contentWindow.console.error, - 'info': iframe.contentWindow.console.info, - 'warn': iframe.contentWindow.console.warn - }; - for (var k in oldLogs) { - (function(oldLog) { - iframe.contentWindow.console[oldLog] = function() { - var message = ''; - for (var i in arguments) { - if (message == '') { - message += arguments[i]; - } else { - message += ' ' + arguments[i]; - } - } - oldLogs[oldLog].call(iframe.contentWindow.console, ...arguments); - window.flutter_inappwebview.nativeCommunication('onConsoleMessage', viewId, [oldLog, message]); - } - })(k); - } - } catch (e) { - console.log(e); - } - - try { - var originalPushState = iframe.contentWindow.history.pushState; - iframe.contentWindow.history.pushState = function (state, unused, url) { - originalPushState.call(iframe.contentWindow.history, state, unused, url); - var iframeUrl = iframe.src; - try { - iframeUrl = iframe.contentWindow.location.href; - } catch (e) { - console.log(e); - } - window.flutter_inappwebview.nativeCommunication('onUpdateVisitedHistory', viewId, [iframeUrl]); - }; - - var originalReplaceState = iframe.contentWindow.history.replaceState; - iframe.contentWindow.history.replaceState = function (state, unused, url) { - originalReplaceState.call(iframe.contentWindow.history, state, unused, url); - var iframeUrl = iframe.src; - try { - iframeUrl = iframe.contentWindow.location.href; - } catch (e) { - console.log(e); - } - window.flutter_inappwebview.nativeCommunication('onUpdateVisitedHistory', viewId, [iframeUrl]); - }; - - var originalOpen = iframe.contentWindow.open; - iframe.contentWindow.open = function (url, target, windowFeatures) { - var newWindow = originalOpen.call(iframe.contentWindow, ...arguments); - var windowId = webView.windowAutoincrementId; - webView.windowAutoincrementId++; - webView.windows[windowId] = newWindow; - window.flutter_inappwebview.nativeCommunication('onCreateWindow', viewId, [windowId, url, target, windowFeatures]).then(function(){}, function(handledByClient) { - if (handledByClient) { - newWindow.close(); - } - }); - return newWindow; - }; - - var originalPrint = iframe.contentWindow.print; - iframe.contentWindow.print = function() { - var iframeUrl = iframe.src; - try { - iframeUrl = iframe.contentWindow.location.href; - } catch (e) { - console.log(e); - } - window.flutter_inappwebview.nativeCommunication('onPrintRequest', viewId, [iframeUrl]); - originalPrint.call(iframe.contentWindow); - }; - - webView.functionMap = { - "window.open": iframe.contentWindow.open, - "window.print": iframe.contentWindow.print, - "window.history.pushState": iframe.contentWindow.history.pushState, - "window.history.replaceState": iframe.contentWindow.history.replaceState, - } - - var initialTitle = iframe.contentDocument.title; - var titleEl = iframe.contentDocument.querySelector('title'); - webView.documentTitle = initialTitle; - window.flutter_inappwebview.nativeCommunication('onTitleChanged', viewId, [initialTitle]); - if (titleEl != null) { - new MutationObserver(function(mutations) { - var title = mutations[0].target.innerText; - if (title != webView.documentTitle) { - webView.documentTitle = title; - window.flutter_inappwebview.nativeCommunication('onTitleChanged', viewId, [title]); - } - }).observe( - titleEl, - { subtree: true, characterData: true, childList: true } - ); - } - - var oldPixelRatio = iframe.contentWindow.devicePixelRatio; - iframe.contentWindow.addEventListener('resize', function (e) { - var newPixelRatio = iframe.contentWindow.devicePixelRatio; - if(newPixelRatio !== oldPixelRatio){ - window.flutter_inappwebview.nativeCommunication('onZoomScaleChanged', viewId, [oldPixelRatio, newPixelRatio]); - oldPixelRatio = newPixelRatio; - } - }); - - iframe.contentWindow.addEventListener('popstate', function (event) { - var iframeUrl = iframe.src; - try { - iframeUrl = iframe.contentWindow.location.href; - } catch (e) { - console.log(e); - } - window.flutter_inappwebview.nativeCommunication('onUpdateVisitedHistory', viewId, [iframeUrl]); - }); - - iframe.contentWindow.addEventListener('scroll', function (event) { - var x = 0; - var y = 0; - try { - x = iframe.contentWindow.scrollX; - y = iframe.contentWindow.scrollY; - } catch (e) { - console.log(e); - } - window.flutter_inappwebview.nativeCommunication('onScrollChanged', viewId, [x, y]); - }); - - iframe.contentWindow.addEventListener('focus', function (event) { - window.flutter_inappwebview.nativeCommunication('onWindowFocus', viewId); - }); - - iframe.contentWindow.addEventListener('blur', function (event) { - window.flutter_inappwebview.nativeCommunication('onWindowBlur', viewId); - }); - } catch (e) { - console.log(e); - } - - try { - - if (!webView.settings.javaScriptCanOpenWindowsAutomatically) { - iframe.contentWindow.open = function() { - throw new Error('JavaScript cannot open windows automatically'); - }; - } - - if (!webView.settings.verticalScrollBarEnabled && !webView.settings.horizontalScrollBarEnabled) { - var style = iframe.contentDocument.createElement('style'); - style.id = "settings.verticalScrollBarEnabled-settings.horizontalScrollBarEnabled"; - style.innerHTML = "body::-webkit-scrollbar { width: 0px; height: 0px; }"; - iframe.contentDocument.head.append(style); - } - - if (webView.settings.disableVerticalScroll) { - var style = iframe.contentDocument.createElement('style'); - style.id = "settings.disableVerticalScroll"; - style.innerHTML = "body { overflow-y: hidden; }"; - iframe.contentDocument.head.append(style); - } - - if (webView.settings.disableHorizontalScroll) { - var style = iframe.contentDocument.createElement('style'); - style.id = "settings.disableHorizontalScroll"; - style.innerHTML = "body { overflow-x: hidden; }"; - iframe.contentDocument.head.append(style); - } - - if (webView.settings.disableContextMenu) { - iframe.contentWindow.addEventListener('contextmenu', webView.disableContextMenuHandler); - } - } catch (e) { - console.log(e); - } - - window.flutter_inappwebview.nativeCommunication('onLoadStop', viewId, [url]); - }); - } - }, - setSettings: function(newSettings) { - var iframe = webView.iframe; - try { - if (webView.settings.javaScriptCanOpenWindowsAutomatically != newSettings.javaScriptCanOpenWindowsAutomatically) { - if (!newSettings.javaScriptCanOpenWindowsAutomatically) { - iframe.contentWindow.open = function() { - throw new Error('JavaScript cannot open windows automatically'); - }; - } else { - iframe.contentWindow.open = webView.functionMap["window.open"]; - } - } - - if (webView.settings.verticalScrollBarEnabled != newSettings.verticalScrollBarEnabled && - webView.settings.horizontalScrollBarEnabled != newSettings.horizontalScrollBarEnabled) { - if (!newSettings.verticalScrollBarEnabled && !newSettings.horizontalScrollBarEnabled) { - var style = iframe.contentDocument.createElement('style'); - style.id = "settings.verticalScrollBarEnabled-settings.horizontalScrollBarEnabled"; - style.innerHTML = "body::-webkit-scrollbar { width: 0px; height: 0px; }"; - iframe.contentDocument.head.append(style); - } else { - var styleElement = iframe.contentDocument.getElementById("settings.verticalScrollBarEnabled-settings.horizontalScrollBarEnabled"); - if (styleElement) { styleElement.remove() } - } - } - - if (webView.settings.disableVerticalScroll != newSettings.disableVerticalScroll) { - if (newSettings.disableVerticalScroll) { - var style = iframe.contentDocument.createElement('style'); - style.id = "settings.disableVerticalScroll"; - style.innerHTML = "body { overflow-y: hidden; }"; - iframe.contentDocument.head.append(style); - } else { - var styleElement = iframe.contentDocument.getElementById("settings.disableVerticalScroll"); - if (styleElement) { styleElement.remove() } - } - } - - if (webView.settings.disableHorizontalScroll != newSettings.disableHorizontalScroll) { - if (newSettings.disableHorizontalScroll) { - var style = iframe.contentDocument.createElement('style'); - style.id = "settings.disableHorizontalScroll"; - style.innerHTML = "body { overflow-x: hidden; }"; - iframe.contentDocument.head.append(style); - } else { - var styleElement = iframe.contentDocument.getElementById("settings.disableHorizontalScroll"); - if (styleElement) { styleElement.remove() } - } - } - - if (webView.settings.disableContextMenu != newSettings.disableContextMenu) { - if (newSettings.disableContextMenu) { - iframe.contentWindow.addEventListener('contextmenu', webView.disableContextMenuHandler); - } else { - iframe.contentWindow.removeEventListener('contextmenu', webView.disableContextMenuHandler); - } - } - } catch (e) { - console.log(e); - } - - webView.settings = newSettings; - }, - reload: function() { - var iframe = webView.iframe; - if (iframe != null && iframe.contentWindow != null) { - try { - iframe.contentWindow.location.reload(); - } catch (e) { - console.log(e); - iframe.contentWindow.location.href = iframe.src; - } - } - }, - goBack: function() { - var iframe = webView.iframe; - if (iframe != null) { - try { - iframe.contentWindow.history.back(); - } catch (e) { - console.log(e); - } +// src/index.ts +(function() { + let _JSON_stringify = window.JSON.stringify; + let _Array_slice = window.Array.prototype.slice; + _Array_slice.call = window.Function.prototype.call; + window.flutter_inappwebview_plugin = { + createFlutterInAppWebView: function(viewId, iframe, iframeContainer, bridgeSecret) { + const iframeId = iframe.id; + const webView = { + viewId, + iframeId, + iframe: null, + iframeContainer: null, + isFullscreen: false, + documentTitle: null, + functionMap: {}, + settings: {}, + javaScriptBridgeEnabled: true, + disableContextMenuHandler: function(event) { + event.preventDefault(); + event.stopPropagation(); + return false; + }, + prepare: function(settings) { + webView.settings = settings; + webView.javaScriptBridgeEnabled = webView.settings.javaScriptBridgeEnabled ?? true; + const javaScriptBridgeOriginAllowList = webView.settings.javaScriptBridgeOriginAllowList; + if (javaScriptBridgeOriginAllowList != null && !javaScriptBridgeOriginAllowList.includes("*")) { + if (javaScriptBridgeOriginAllowList.length === 0) { + webView.javaScriptBridgeEnabled = false; + } + } + document.addEventListener("fullscreenchange", function(event) { + if (document.fullscreenElement && document.fullscreenElement.id == iframeId) { + webView.isFullscreen = true; + _nativeCommunication("onEnterFullscreen", viewId); + } else if (!document.fullscreenElement && webView.isFullscreen) { + webView.isFullscreen = false; + _nativeCommunication("onExitFullscreen", viewId); + } else { + webView.isFullscreen = false; + } + }); + if (iframe != null) { + webView.iframe = iframe; + webView.iframeContainer = iframeContainer; + iframe.addEventListener("load", function(event) { + if (iframe.contentWindow == null) { + return; + } + const userScriptsAtStart = _nativeCommunication("getUserOnlyScriptsAt", viewId, [0 /* AT_DOCUMENT_START */]); + const userScriptsAtEnd = _nativeCommunication("getUserOnlyScriptsAt", viewId, [1 /* AT_DOCUMENT_END */]); + try { + let javaScriptBridgeEnabled = webView.javaScriptBridgeEnabled; + if (javaScriptBridgeOriginAllowList != null) { + javaScriptBridgeEnabled = javaScriptBridgeOriginAllowList.map((allowedOriginRule) => new RegExp(allowedOriginRule)).some((rx) => { + return rx.test(iframe.contentWindow.location.origin); + }); } - }, - goForward: function() { - var iframe = webView.iframe; - if (iframe != null) { - try { - iframe.contentWindow.history.forward(); - } catch (e) { - console.log(e); + if (javaScriptBridgeEnabled) { + const javaScriptBridgeName = _nativeCommunication("getJavaScriptBridgeName", viewId); + iframe.contentWindow[javaScriptBridgeName] = { + callHandler: function() { + let origin = ""; + let requestUrl = ""; + try { + origin = iframe.contentWindow.location.origin; + } catch (_) { + } + try { + requestUrl = iframe.contentWindow.location.href; + } catch (_) { + } + return _nativeCommunication( + "onCallJsHandler", + viewId, + [arguments[0], _JSON_stringify({ + "origin": origin, + "requestUrl": requestUrl, + "isMainFrame": true, + "_bridgeSecret": bridgeSecret, + "args": _JSON_stringify(_Array_slice.call(arguments, 1)) + })] + ); } + }; } - }, - goBackOrForward: function(steps) { - var iframe = webView.iframe; - if (iframe != null) { - try { - iframe.contentWindow.history.go(steps); - } catch (e) { - console.log(e); + } catch (e) { + console.log(e); + } + for (const userScript of [...userScriptsAtStart, ...userScriptsAtEnd]) { + let ifStatement = "if ("; + let source = userScript.source; + if (userScript.allowedOriginRules != null && !userScript.allowedOriginRules.includes("*")) { + if (userScript.allowedOriginRules.length === 0) { + source = ""; + } + let jsRegExpArray = "["; + for (const allowedOriginRule of userScript.allowedOriginRules) { + if (jsRegExpArray.length > 1) { + jsRegExpArray += ","; } + jsRegExpArray += `new RegExp('${allowedOriginRule.replace("'", "\\'")}')`; + } + if (jsRegExpArray.length > 1) { + jsRegExpArray += "]"; + ifStatement += `${jsRegExpArray}.some(function(rx) { return rx.test(window.location.origin); })`; + } } - }, - evaluateJavascript: function(source) { - var iframe = webView.iframe; - var result = null; - if (iframe != null) { - try { - result = JSON.stringify(iframe.contentWindow.eval(source)); - } catch (e) {} - } - return result; - }, - stopLoading: function(steps) { - var iframe = webView.iframe; - if (iframe != null) { - try { - iframe.contentWindow.stop(); - } catch (e) { - console.log(e); - } - } - }, - getUrl: function() { - var iframe = webView.iframe; - var url = iframe.src; - try { - url = iframe.contentWindow.location.href; - } catch (e) { - console.log(e); - } - return url; - }, - getTitle: function() { - var iframe = webView.iframe; - var title = null; - try { - title = iframe.contentDocument.title; - } catch (e) { - console.log(e); - } - return title; - }, - injectJavascriptFileFromUrl: function(urlFile, scriptHtmlTagAttributes) { - var iframe = webView.iframe; - try { - var d = iframe.contentDocument; - var script = d.createElement('script'); - for (var key of Object.keys(scriptHtmlTagAttributes)) { - if (scriptHtmlTagAttributes[key] != null) { - script[key] = scriptHtmlTagAttributes[key]; - } - } - if (script.id != null) { - script.onload = function() { - window.flutter_inappwebview.nativeCommunication('onInjectedScriptLoaded', webView.viewId, [script.id]); - } - script.onerror = function() { - window.flutter_inappwebview.nativeCommunication('onInjectedScriptError', webView.viewId, [script.id]); + webView.evaluateJavascript(ifStatement.length > 4 ? `${ifStatement}) { ${source} }` : source); + } + let url = iframe.src; + try { + url = iframe.contentWindow.location.href; + } catch (e) { + console.log(e); + } + _nativeCommunication("onLoadStart", viewId, [url]); + try { + const oldLogs = { + "log": iframe.contentWindow.console.log, + "debug": iframe.contentWindow.console.debug, + "error": iframe.contentWindow.console.error, + "info": iframe.contentWindow.console.info, + "warn": iframe.contentWindow.console.warn + }; + for (const k in oldLogs) { + (function(oldLog) { + iframe.contentWindow.console[oldLog] = function() { + var message = ""; + for (var i in arguments) { + if (message == "") { + message += arguments[i]; + } else { + message += " " + arguments[i]; } - } - script.src = urlFile; - if (d.body != null) { - d.body.appendChild(script); - } - } catch (e) { - console.log(e); + } + oldLogs[oldLog].call(iframe.contentWindow.console, ...arguments); + _nativeCommunication("onConsoleMessage", viewId, [oldLog, message]); + }; + })(k); } - }, - injectCSSCode: function(source) { - var iframe = webView.iframe; - try { - var d = iframe.contentDocument; - var style = d.createElement('style'); - style.innerHTML = source; - if (d.head != null) { - d.head.appendChild(style); - } - } catch (e) { + } catch (e) { + console.log(e); + } + try { + const originalPushState = iframe.contentWindow.history.pushState; + iframe.contentWindow.history.pushState = function(state, unused, url2) { + originalPushState.call(iframe.contentWindow.history, state, unused, url2); + let iframeUrl = iframe.src; + try { + iframeUrl = iframe.contentWindow.location.href; + } catch (e) { console.log(e); - } - }, - injectCSSFileFromUrl: function(urlFile, cssLinkHtmlTagAttributes) { - var iframe = webView.iframe; - try { - var d = iframe.contentDocument; - var link = d.createElement('link'); - for (var key of Object.keys(cssLinkHtmlTagAttributes)) { - if (cssLinkHtmlTagAttributes[key] != null) { - link[key] = cssLinkHtmlTagAttributes[key]; - } - } - link.type = 'text/css'; - var alternateStylesheet = ""; - if (cssLinkHtmlTagAttributes.alternateStylesheet) { - alternateStylesheet = "alternate "; - } - link.rel = alternateStylesheet + "stylesheet"; - link.href = urlFile; - if (d.head != null) { - d.head.appendChild(link); - } - } catch (e) { + } + _nativeCommunication("onUpdateVisitedHistory", viewId, [iframeUrl]); + }; + const originalReplaceState = iframe.contentWindow.history.replaceState; + iframe.contentWindow.history.replaceState = function(state, unused, url2) { + originalReplaceState.call(iframe.contentWindow.history, state, unused, url2); + let iframeUrl = iframe.src; + try { + iframeUrl = iframe.contentWindow.location.href; + } catch (e) { console.log(e); - } - }, - scrollTo: function(x, y, animated) { - var iframe = webView.iframe; - try { - if (animated) { - iframe.contentWindow.scrollTo({top: y, left: x, behavior: 'smooth'}); - } else { - iframe.contentWindow.scrollTo(x, y); + } + _nativeCommunication("onUpdateVisitedHistory", viewId, [iframeUrl]); + }; + const originalClose = iframe.contentWindow.close; + iframe.contentWindow.close = function() { + originalClose.call(iframe.contentWindow); + _nativeCommunication("onCloseWindow", viewId); + }; + const originalOpen = iframe.contentWindow.open; + iframe.contentWindow.open = function(url2, target, windowFeatures) { + const newWindow = originalOpen.call(iframe.contentWindow, ...arguments); + _nativeCommunication("onCreateWindow", viewId, [url2, target, windowFeatures]).then(function(handledByClient) { + if (handledByClient) { + newWindow?.close(); } - } catch (e) { + }); + return newWindow; + }; + const originalPrint = iframe.contentWindow.print; + iframe.contentWindow.print = function() { + let iframeUrl = iframe.src; + try { + iframeUrl = iframe.contentWindow.location.href; + } catch (e) { console.log(e); - } - }, - scrollBy: function(x, y, animated) { - var iframe = webView.iframe; - try { - if (animated) { - iframe.contentWindow.scrollBy({top: y, left: x, behavior: 'smooth'}); - } else { - iframe.contentWindow.scrollBy(x, y); + } + _nativeCommunication("onPrintRequest", viewId, [iframeUrl]); + originalPrint.call(iframe.contentWindow); + }; + webView.functionMap = { + "window.open": iframe.contentWindow.open + }; + const initialTitle = iframe.contentDocument?.title; + const titleEl = iframe.contentDocument?.querySelector("title"); + webView.documentTitle = initialTitle; + _nativeCommunication("onTitleChanged", viewId, [initialTitle]); + if (titleEl != null) { + new MutationObserver(function(mutations) { + const title = mutations[0].target.innerText; + if (title != webView.documentTitle) { + webView.documentTitle = title; + _nativeCommunication("onTitleChanged", viewId, [title]); } - } catch (e) { - console.log(e); + }).observe( + titleEl, + { subtree: true, characterData: true, childList: true } + ); } - }, - printCurrentPage: function() { - var iframe = webView.iframe; - try { - iframe.contentWindow.print(); - } catch (e) { + let oldPixelRatio = iframe.contentWindow.devicePixelRatio; + iframe.contentWindow.addEventListener("resize", function(e) { + const newPixelRatio = iframe.contentWindow.devicePixelRatio; + if (newPixelRatio !== oldPixelRatio) { + _nativeCommunication("onZoomScaleChanged", viewId, [oldPixelRatio, newPixelRatio]); + oldPixelRatio = newPixelRatio; + } + }); + iframe.contentWindow.addEventListener("popstate", function(event2) { + let iframeUrl = iframe.src; + try { + iframeUrl = iframe.contentWindow.location.href; + } catch (e) { console.log(e); - } - }, - getContentHeight: function() { - var iframe = webView.iframe; - try { - return iframe.contentDocument.documentElement.scrollHeight; - } catch (e) { + } + _nativeCommunication("onUpdateVisitedHistory", viewId, [iframeUrl]); + }); + iframe.contentWindow.addEventListener("scroll", function(event2) { + let x = 0; + let y = 0; + try { + x = iframe.contentWindow.scrollX; + y = iframe.contentWindow.scrollY; + } catch (e) { console.log(e); + } + _nativeCommunication("onScrollChanged", viewId, [x, y]); + }); + iframe.contentWindow.addEventListener("focus", function(event2) { + _nativeCommunication("onWindowFocus", viewId); + }); + iframe.contentWindow.addEventListener("blur", function(event2) { + _nativeCommunication("onWindowBlur", viewId); + }); + } catch (e) { + console.log(e); + } + try { + if (!webView.settings.javaScriptCanOpenWindowsAutomatically) { + iframe.contentWindow.open = function() { + throw new Error("JavaScript cannot open windows automatically"); + }; } - return null; - }, - getContentWidth: function() { - var iframe = webView.iframe; - try { - return iframe.contentDocument.documentElement.scrollWidth; - } catch (e) { - console.log(e); + if (!webView.settings.verticalScrollBarEnabled && !webView.settings.horizontalScrollBarEnabled) { + const style = iframe.contentDocument?.createElement("style"); + if (style != null) { + style.id = "settings.verticalScrollBarEnabled-settings.horizontalScrollBarEnabled"; + style.innerHTML = "body::-webkit-scrollbar { width: 0px; height: 0px; }"; + iframe.contentDocument?.head.append(style); + } } - return null; - }, - getSelectedText: function() { - var iframe = webView.iframe; - try { - var txt; - var w = iframe.contentWindow; - if (w.getSelection) { - txt = w.getSelection().toString(); - } else if (w.document.getSelection) { - txt = w.document.getSelection().toString(); - } else if (w.document.selection) { - txt = w.document.selection.createRange().text; - } - return txt; - } catch (e) { - console.log(e); + if (webView.settings.disableVerticalScroll) { + const style = iframe.contentDocument?.createElement("style"); + if (style != null) { + style.id = "settings.disableVerticalScroll"; + style.innerHTML = "body { overflow-y: hidden; }"; + iframe.contentDocument?.head.append(style); + } } - return null; - }, - getScrollX: function() { - var iframe = webView.iframe; - try { - return iframe.contentWindow.scrollX; - } catch (e) { - console.log(e); + if (webView.settings.disableHorizontalScroll) { + const style = iframe.contentDocument?.createElement("style"); + if (style != null) { + style.id = "settings.disableHorizontalScroll"; + style.innerHTML = "body { overflow-x: hidden; }"; + iframe.contentDocument?.head.append(style); + } } - return null; - }, - getScrollY: function() { - var iframe = webView.iframe; - try { - return iframe.contentWindow.scrollY; - } catch (e) { - console.log(e); + if (webView.settings.disableContextMenu) { + iframe.contentWindow.addEventListener("contextmenu", webView.disableContextMenuHandler); } - return null; - }, - isSecureContext: function() { - var iframe = webView.iframe; - try { - return iframe.contentWindow.isSecureContext; - } catch (e) { - console.log(e); + } catch (e) { + console.log(e); + } + _nativeCommunication("onLoadStop", viewId, [url]); + try { + iframe.contentWindow.dispatchEvent(new Event("flutterInAppWebViewPlatformReady")); + } catch (e) { + console.log(e); + } + }); + } + }, + setSettings: function(newSettings) { + const iframe2 = webView.iframe; + if (iframe2 == null) { + return; + } + try { + if (webView.settings.javaScriptCanOpenWindowsAutomatically != newSettings.javaScriptCanOpenWindowsAutomatically) { + if (!newSettings.javaScriptCanOpenWindowsAutomatically) { + iframe2.contentWindow.open = function() { + throw new Error("JavaScript cannot open windows automatically"); + }; + } else { + iframe2.contentWindow.open = webView.functionMap["window.open"]; + } + } + if (webView.settings.verticalScrollBarEnabled != newSettings.verticalScrollBarEnabled && webView.settings.horizontalScrollBarEnabled != newSettings.horizontalScrollBarEnabled) { + if (!newSettings.verticalScrollBarEnabled && !newSettings.horizontalScrollBarEnabled) { + const style = iframe2.contentDocument?.createElement("style"); + if (style != null) { + style.id = "settings.verticalScrollBarEnabled-settings.horizontalScrollBarEnabled"; + style.innerHTML = "body::-webkit-scrollbar { width: 0px; height: 0px; }"; + iframe2.contentDocument?.head.append(style); } - return false; - }, - canScrollVertically: function() { - var iframe = webView.iframe; - try { - return iframe.contentDocument.body.scrollHeight > iframe.contentWindow.innerHeight; - } catch (e) { - console.log(e); + } else { + const styleElement = iframe2.contentDocument?.getElementById("settings.verticalScrollBarEnabled-settings.horizontalScrollBarEnabled"); + if (styleElement) { + styleElement.remove(); } - return false; - }, - canScrollHorizontally: function() { - var iframe = webView.iframe; - try { - return iframe.contentDocument.body.scrollWidth > iframe.contentWindow.innerWidth; - } catch (e) { - console.log(e); - } - return false; - }, - getSize: function() { - var iframeContainer = webView.iframeContainer; - var width = 0.0; - var height = 0.0; - if (iframeContainer.style.width != null && iframeContainer.style.width != '' && iframeContainer.style.width.indexOf('px') > 0) { - width = parseFloat(iframeContainer.style.width); + } + } + if (webView.settings.disableVerticalScroll != newSettings.disableVerticalScroll) { + if (newSettings.disableVerticalScroll) { + const style = iframe2.contentDocument?.createElement("style"); + if (style != null) { + style.id = "settings.disableVerticalScroll"; + style.innerHTML = "body { overflow-y: hidden; }"; + iframe2.contentDocument?.head.append(style); } - if (width == null || width == 0.0) { - width = iframeContainer.getBoundingClientRect().width; + } else { + const styleElement = iframe2.contentDocument?.getElementById("settings.disableVerticalScroll"); + if (styleElement) { + styleElement.remove(); } - if (iframeContainer.style.height != null && iframeContainer.style.height != '' && iframeContainer.style.height.indexOf('px') > 0) { - height = parseFloat(iframeContainer.style.height); + } + } + if (webView.settings.disableHorizontalScroll != newSettings.disableHorizontalScroll) { + if (newSettings.disableHorizontalScroll) { + const style = iframe2.contentDocument?.createElement("style"); + if (style != null) { + style.id = "settings.disableHorizontalScroll"; + style.innerHTML = "body { overflow-x: hidden; }"; + iframe2.contentDocument?.head.append(style); } - if (height == null || height == 0.0) { - height = iframeContainer.getBoundingClientRect().height; + } else { + const styleElement = iframe2.contentDocument?.getElementById("settings.disableHorizontalScroll"); + if (styleElement) { + styleElement.remove(); } - - return { - width: width, - height: height - }; + } + } + if (webView.settings.disableContextMenu != newSettings.disableContextMenu) { + if (newSettings.disableContextMenu) { + iframe2.contentWindow?.addEventListener("contextmenu", webView.disableContextMenuHandler); + } else { + iframe2.contentWindow?.removeEventListener("contextmenu", webView.disableContextMenuHandler); + } + } + } catch (e) { + console.log(e); + } + webView.settings = newSettings; + }, + reload: function() { + var iframe2 = webView.iframe; + if (iframe2 != null && iframe2.contentWindow != null) { + try { + iframe2.contentWindow.location.reload(); + } catch (e) { + console.log(e); + iframe2.contentWindow.location.href = iframe2.src; } - }; - - return webView; + } + }, + goBack: function() { + var iframe2 = webView.iframe; + if (iframe2 != null) { + try { + iframe2.contentWindow?.history.back(); + } catch (e) { + console.log(e); + } + } + }, + goForward: function() { + var iframe2 = webView.iframe; + if (iframe2 != null) { + try { + iframe2.contentWindow?.history.forward(); + } catch (e) { + console.log(e); + } + } + }, + goBackOrForward: function(steps) { + var iframe2 = webView.iframe; + if (iframe2 != null) { + try { + iframe2.contentWindow?.history.go(steps); + } catch (e) { + console.log(e); + } + } + }, + evaluateJavascript: function(source) { + const iframe2 = webView.iframe; + let result = null; + if (iframe2 != null) { + try { + result = JSON.stringify(iframe2.contentWindow?.eval(source)); + } catch (e) { + } + } + return result; + }, + stopLoading: function() { + const iframe2 = webView.iframe; + if (iframe2 != null) { + try { + iframe2.contentWindow?.stop(); + } catch (e) { + console.log(e); + } + } + }, + getUrl: function() { + const iframe2 = webView.iframe; + let url = iframe2?.src; + try { + url = iframe2?.contentWindow?.location.href; + } catch (e) { + console.log(e); + } + return url; + }, + getTitle: function() { + const iframe2 = webView.iframe; + let title = null; + try { + title = iframe2?.contentDocument?.title; + } catch (e) { + console.log(e); + } + return title; + }, + injectJavascriptFileFromUrl: function(urlFile, scriptHtmlTagAttributes) { + const iframe2 = webView.iframe; + try { + const d = iframe2?.contentDocument; + if (d == null) { + return; + } + const script = d.createElement("script"); + for (const key of Object.keys(scriptHtmlTagAttributes)) { + if (scriptHtmlTagAttributes[key] != null) { + script[key] = scriptHtmlTagAttributes[key]; + } + } + if (script.id != null) { + script.onload = function() { + _nativeCommunication("onInjectedScriptLoaded", webView.viewId, [script.id]); + }; + script.onerror = function() { + _nativeCommunication("onInjectedScriptError", webView.viewId, [script.id]); + }; + } + script.src = urlFile; + if (d.body != null) { + d.body.appendChild(script); + } + } catch (e) { + console.log(e); + } + }, + injectCSSCode: function(source) { + const iframe2 = webView.iframe; + try { + const d = iframe2?.contentDocument; + if (d == null) { + return; + } + const style = d.createElement("style"); + style.innerHTML = source; + if (d.head != null) { + d.head.appendChild(style); + } + } catch (e) { + console.log(e); + } + }, + injectCSSFileFromUrl: function(urlFile, cssLinkHtmlTagAttributes) { + const iframe2 = webView.iframe; + try { + const d = iframe2?.contentDocument; + if (d == null) { + return; + } + const link = d.createElement("link"); + for (const key of Object.keys(cssLinkHtmlTagAttributes)) { + if (cssLinkHtmlTagAttributes[key] != null) { + link[key] = cssLinkHtmlTagAttributes[key]; + } + } + link.type = "text/css"; + var alternateStylesheet = ""; + if (cssLinkHtmlTagAttributes.alternateStylesheet) { + alternateStylesheet = "alternate "; + } + link.rel = alternateStylesheet + "stylesheet"; + link.href = urlFile; + if (d.head != null) { + d.head.appendChild(link); + } + } catch (e) { + console.log(e); + } + }, + scrollTo: function(x, y, animated) { + const iframe2 = webView.iframe; + try { + if (animated) { + iframe2?.contentWindow?.scrollTo({ top: y, left: x, behavior: "smooth" }); + } else { + iframe2?.contentWindow?.scrollTo(x, y); + } + } catch (e) { + console.log(e); + } + }, + scrollBy: function(x, y, animated) { + const iframe2 = webView.iframe; + try { + if (animated) { + iframe2?.contentWindow?.scrollBy({ top: y, left: x, behavior: "smooth" }); + } else { + iframe2?.contentWindow?.scrollBy(x, y); + } + } catch (e) { + console.log(e); + } + }, + printCurrentPage: function() { + const iframe2 = webView.iframe; + try { + iframe2?.contentWindow?.print(); + } catch (e) { + console.log(e); + } + }, + getContentHeight: function() { + const iframe2 = webView.iframe; + try { + return iframe2?.contentDocument?.documentElement.scrollHeight; + } catch (e) { + console.log(e); + } + return null; + }, + getContentWidth: function() { + const iframe2 = webView.iframe; + try { + return iframe2?.contentDocument?.documentElement.scrollWidth; + } catch (e) { + console.log(e); + } + return null; + }, + getSelectedText: function() { + const iframe2 = webView.iframe; + try { + let txt; + const w = iframe2?.contentWindow; + if (w == null) { + return null; + } + if (w.getSelection) { + txt = w.getSelection()?.toString(); + } else if (w.document.getSelection) { + txt = w.document.getSelection()?.toString(); + } else if (w.document.selection) { + txt = w.document.selection.createRange().text; + } + return txt; + } catch (e) { + console.log(e); + } + return null; + }, + getScrollX: function() { + const iframe2 = webView.iframe; + try { + return iframe2?.contentWindow?.scrollX; + } catch (e) { + console.log(e); + } + return null; + }, + getScrollY: function() { + const iframe2 = webView.iframe; + try { + return iframe2?.contentWindow?.scrollY; + } catch (e) { + console.log(e); + } + return null; + }, + isSecureContext: function() { + const iframe2 = webView.iframe; + try { + return iframe2?.contentWindow?.isSecureContext ?? false; + } catch (e) { + console.log(e); + } + return false; + }, + canScrollVertically: function() { + const iframe2 = webView.iframe; + try { + return (iframe2?.contentDocument?.body.scrollHeight ?? 0) > (iframe2?.contentWindow?.innerHeight ?? 0); + } catch (e) { + console.log(e); + } + return false; + }, + canScrollHorizontally: function() { + const iframe2 = webView.iframe; + try { + return (iframe2?.contentDocument?.body.scrollWidth ?? 0) > (iframe2?.contentWindow?.innerWidth ?? 0); + } catch (e) { + console.log(e); + } + return false; + }, + getSize: function() { + const iframeContainer2 = webView.iframeContainer; + let width = 0; + let height = 0; + if (iframeContainer2 != null) { + if (iframeContainer2.style.width != null && iframeContainer2.style.width != "" && iframeContainer2.style.width.indexOf("px") > 0) { + width = parseFloat(iframeContainer2.style.width); + } + if (width == null || width == 0) { + width = iframeContainer2.getBoundingClientRect().width; + } + if (iframeContainer2.style.height != null && iframeContainer2.style.height != "" && iframeContainer2.style.height.indexOf("px") > 0) { + height = parseFloat(iframeContainer2.style.height); + } + if (height == null || height == 0) { + height = iframeContainer2.getBoundingClientRect().height; + } + } + return { + width, + height + }; + } + }; + return webView; }, getCookieExpirationDate: function(timestamp) { - return (new Date(timestamp)).toUTCString(); + return new Date(timestamp).toUTCString(); + }, + nativeAsyncCommunication: function(method, viewId, args) { + throw new Error("Method not implemented."); + }, + nativeSyncCommunication: function(method, viewId, args) { + throw new Error("Method not implemented."); + }, + nativeCommunication: function(method, viewId, args) { + try { + const result = window.flutter_inappwebview_plugin.nativeSyncCommunication(method, viewId, args); + return result != null ? JSON.parse(result) : null; + } catch (e1) { + try { + const promise = window.flutter_inappwebview_plugin.nativeAsyncCommunication(method, viewId, args); + return promise.then(function(result) { + return result != null ? JSON.parse(result) : null; + }); + } catch (e2) { + return null; + } + } } -}; \ No newline at end of file + }; + let _nativeCommunication = window.flutter_inappwebview_plugin.nativeCommunication; +})(); +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vLi4vd2ViX3N1cHBvcnQvc3JjL2luZGV4LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJpbXBvcnQge1xuICBJbkFwcFdlYlZpZXcsXG4gIEluQXBwV2ViVmlld1BsdWdpbixcbiAgSW5BcHBXZWJWaWV3U2V0dGluZ3MsXG4gIEphdmFTY3JpcHRCcmlkZ2VIYW5kbGVyLFxuICBVc2VyU2NyaXB0LFxuICBVc2VyU2NyaXB0SW5qZWN0aW9uVGltZVxufSBmcm9tIFwiLi90eXBlc1wiO1xuXG5kZWNsYXJlIGdsb2JhbCB7XG4gIGludGVyZmFjZSBXaW5kb3cge1xuICAgIGZsdXR0ZXJfaW5hcHB3ZWJ2aWV3X3BsdWdpbjogSW5BcHBXZWJWaWV3UGx1Z2luO1xuICAgIGZsdXR0ZXJfaW5hcHB3ZWJ2aWV3PzogSmF2YVNjcmlwdEJyaWRnZUhhbmRsZXIgfCBudWxsO1xuICAgIGNvbnNvbGU6IENvbnNvbGU7XG5cbiAgICBldmFsKHg6IHN0cmluZyk6IGFueTtcbiAgfVxufVxuXG4oZnVuY3Rpb24gKCkge1xuICBsZXQgX0pTT05fc3RyaW5naWZ5ID0gd2luZG93LkpTT04uc3RyaW5naWZ5O1xuICBsZXQgX0FycmF5X3NsaWNlID0gd2luZG93LkFycmF5LnByb3RvdHlwZS5zbGljZTtcbiAgX0FycmF5X3NsaWNlLmNhbGwgPSB3aW5kb3cuRnVuY3Rpb24ucHJvdG90eXBlLmNhbGw7XG5cbiAgd2luZG93LmZsdXR0ZXJfaW5hcHB3ZWJ2aWV3X3BsdWdpbiA9IHtcbiAgICBjcmVhdGVGbHV0dGVySW5BcHBXZWJWaWV3OiBmdW5jdGlvbiAodmlld0lkOiBudW1iZXIgfCBzdHJpbmcsIGlmcmFtZTogSFRNTElGcmFtZUVsZW1lbnQsIGlmcmFtZUNvbnRhaW5lcjogSFRNTERpdkVsZW1lbnQsIGJyaWRnZVNlY3JldDogc3RyaW5nKSB7XG4gICAgICBjb25zdCBpZnJhbWVJZCA9IGlmcmFtZS5pZDtcbiAgICAgIGNvbnN0IHdlYlZpZXc6IEluQXBwV2ViVmlldyA9IHtcbiAgICAgICAgdmlld0lkOiB2aWV3SWQsXG4gICAgICAgIGlmcmFtZUlkOiBpZnJhbWVJZCxcbiAgICAgICAgaWZyYW1lOiBudWxsLFxuICAgICAgICBpZnJhbWVDb250YWluZXI6IG51bGwsXG4gICAgICAgIGlzRnVsbHNjcmVlbjogZmFsc2UsXG4gICAgICAgIGRvY3VtZW50VGl0bGU6IG51bGwsXG4gICAgICAgIGZ1bmN0aW9uTWFwOiB7fSxcbiAgICAgICAgc2V0dGluZ3M6IHt9LFxuICAgICAgICBqYXZhU2NyaXB0QnJpZGdlRW5hYmxlZDogdHJ1ZSxcbiAgICAgICAgZGlzYWJsZUNvbnRleHRNZW51SGFuZGxlcjogZnVuY3Rpb24gKGV2ZW50OiBFdmVudCkge1xuICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9LFxuICAgICAgICBwcmVwYXJlOiBmdW5jdGlvbiAoc2V0dGluZ3M6IEluQXBwV2ViVmlld1NldHRpbmdzKSB7XG4gICAgICAgICAgd2ViVmlldy5zZXR0aW5ncyA9IHNldHRpbmdzO1xuXG4gICAgICAgICAgd2ViVmlldy5qYXZhU2NyaXB0QnJpZGdlRW5hYmxlZCA9IHdlYlZpZXcuc2V0dGluZ3MuamF2YVNjcmlwdEJyaWRnZUVuYWJsZWQgPz8gdHJ1ZTtcbiAgICAgICAgICBjb25zdCBqYXZhU2NyaXB0QnJpZGdlT3JpZ2luQWxsb3dMaXN0ID0gd2ViVmlldy5zZXR0aW5ncy5qYXZhU2NyaXB0QnJpZGdlT3JpZ2luQWxsb3dMaXN0O1xuICAgICAgICAgIGlmIChqYXZhU2NyaXB0QnJpZGdlT3JpZ2luQWxsb3dMaXN0ICE9IG51bGwgJiYgIWphdmFTY3JpcHRCcmlkZ2VPcmlnaW5BbGxvd0xpc3QuaW5jbHVkZXMoXCIqXCIpKSB7XG4gICAgICAgICAgICBpZiAoamF2YVNjcmlwdEJyaWRnZU9yaWdpbkFsbG93TGlzdC5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgLy8gYW4gZW1wdHkgbGlzdCBtZWFucyB0aGF0IHRoZSBKYXZhU2NyaXB0IEJyaWRnZSBpcyBub3QgYWxsb3dlZCBmb3IgYW55IG9yaWdpbi5cbiAgICAgICAgICAgICAgd2ViVmlldy5qYXZhU2NyaXB0QnJpZGdlRW5hYmxlZCA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2Z1bGxzY3JlZW5jaGFuZ2UnLCBmdW5jdGlvbiAoZXZlbnQ6IEV2ZW50KSB7XG4gICAgICAgICAgICAvLyBkb2N1bWVudC5mdWxsc2NyZWVuRWxlbWVudCB3aWxsIHBvaW50IHRvIHRoZSBlbGVtZW50IHRoYXRcbiAgICAgICAgICAgIC8vIGlzIGluIGZ1bGxzY3JlZW4gbW9kZSBpZiB0aGVyZSBpcyBvbmUuIElmIHRoZXJlIGlzbid0IG9uZSxcbiAgICAgICAgICAgIC8vIHRoZSB2YWx1ZSBvZiB0aGUgcHJvcGVydHkgaXMgbnVsbC5cbiAgICAgICAgICAgIGlmIChkb2N1bWVudC5mdWxsc2NyZWVuRWxlbWVudCAmJiBkb2N1bWVudC5mdWxsc2NyZWVuRWxlbWVudC5pZCA9PSBpZnJhbWVJZCkge1xuICAgICAgICAgICAgICB3ZWJWaWV3LmlzRnVsbHNjcmVlbiA9IHRydWU7XG4gICAgICAgICAgICAgIF9uYXRpdmVDb21tdW5pY2F0aW9uKCdvbkVudGVyRnVsbHNjcmVlbicsIHZpZXdJZCk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCFkb2N1bWVudC5mdWxsc2NyZWVuRWxlbWVudCAmJiB3ZWJWaWV3LmlzRnVsbHNjcmVlbikge1xuICAgICAgICAgICAgICB3ZWJWaWV3LmlzRnVsbHNjcmVlbiA9IGZhbHNlO1xuICAgICAgICAgICAgICBfbmF0aXZlQ29tbXVuaWNhdGlvbignb25FeGl0RnVsbHNjcmVlbicsIHZpZXdJZCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICB3ZWJWaWV3LmlzRnVsbHNjcmVlbiA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgaWYgKGlmcmFtZSAhPSBudWxsKSB7XG4gICAgICAgICAgICB3ZWJWaWV3LmlmcmFtZSA9IGlmcmFtZTtcbiAgICAgICAgICAgIHdlYlZpZXcuaWZyYW1lQ29udGFpbmVyID0gaWZyYW1lQ29udGFpbmVyO1xuICAgICAgICAgICAgaWZyYW1lLmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWQnLCBmdW5jdGlvbiAoZXZlbnQ6IEV2ZW50KSB7XG4gICAgICAgICAgICAgIGlmIChpZnJhbWUuY29udGVudFdpbmRvdyA9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgY29uc3QgdXNlclNjcmlwdHNBdFN0YXJ0ID0gX25hdGl2ZUNvbW11bmljYXRpb248VXNlclNjcmlwdFtdPignZ2V0VXNlck9ubHlTY3JpcHRzQXQnLCB2aWV3SWQsIFtVc2VyU2NyaXB0SW5qZWN0aW9uVGltZS5BVF9ET0NVTUVOVF9TVEFSVF0pO1xuICAgICAgICAgICAgICBjb25zdCB1c2VyU2NyaXB0c0F0RW5kID0gX25hdGl2ZUNvbW11bmljYXRpb248VXNlclNjcmlwdFtdPignZ2V0VXNlck9ubHlTY3JpcHRzQXQnLCB2aWV3SWQsIFtVc2VyU2NyaXB0SW5qZWN0aW9uVGltZS5BVF9ET0NVTUVOVF9FTkRdKTtcblxuICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGxldCBqYXZhU2NyaXB0QnJpZGdlRW5hYmxlZCA9IHdlYlZpZXcuamF2YVNjcmlwdEJyaWRnZUVuYWJsZWQ7XG4gICAgICAgICAgICAgICAgaWYgKGphdmFTY3JpcHRCcmlkZ2VPcmlnaW5BbGxvd0xpc3QgIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgamF2YVNjcmlwdEJyaWRnZUVuYWJsZWQgPSBqYXZhU2NyaXB0QnJpZGdlT3JpZ2luQWxsb3dMaXN0XG4gICAgICAgICAgICAgICAgICAgICAgLm1hcChhbGxvd2VkT3JpZ2luUnVsZSA9PiBuZXcgUmVnRXhwKGFsbG93ZWRPcmlnaW5SdWxlKSlcbiAgICAgICAgICAgICAgICAgICAgICAuc29tZSgocngpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiByeC50ZXN0KGlmcmFtZS5jb250ZW50V2luZG93IS5sb2NhdGlvbi5vcmlnaW4pO1xuICAgICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChqYXZhU2NyaXB0QnJpZGdlRW5hYmxlZCkge1xuICAgICAgICAgICAgICAgICAgY29uc3QgamF2YVNjcmlwdEJyaWRnZU5hbWUgPSBfbmF0aXZlQ29tbXVuaWNhdGlvbjxzdHJpbmc+KCdnZXRKYXZhU2NyaXB0QnJpZGdlTmFtZScsIHZpZXdJZCk7XG4gICAgICAgICAgICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgICAgICAgICAgICBpZnJhbWUuY29udGVudFdpbmRvdyFbamF2YVNjcmlwdEJyaWRnZU5hbWVdID0ge1xuICAgICAgICAgICAgICAgICAgICBjYWxsSGFuZGxlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgIGxldCBvcmlnaW4gPSAnJztcbiAgICAgICAgICAgICAgICAgICAgICBsZXQgcmVxdWVzdFVybCA9ICcnO1xuICAgICAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBvcmlnaW4gPSBpZnJhbWUuY29udGVudFdpbmRvdyEubG9jYXRpb24ub3JpZ2luO1xuICAgICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKF8pIHtcbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlcXVlc3RVcmwgPSBpZnJhbWUuY29udGVudFdpbmRvdyEubG9jYXRpb24uaHJlZjtcbiAgICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChfKSB7XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBfbmF0aXZlQ29tbXVuaWNhdGlvbignb25DYWxsSnNIYW5kbGVyJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgdmlld0lkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBbYXJndW1lbnRzWzBdLCBfSlNPTl9zdHJpbmdpZnkoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICdvcmlnaW4nOiBvcmlnaW4sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3JlcXVlc3RVcmwnOiByZXF1ZXN0VXJsLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICdpc01haW5GcmFtZSc6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ19icmlkZ2VTZWNyZXQnOiBicmlkZ2VTZWNyZXQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2FyZ3MnOiBfSlNPTl9zdHJpbmdpZnkoX0FycmF5X3NsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSldKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgfSBhcyBKYXZhU2NyaXB0QnJpZGdlSGFuZGxlcjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhlKTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIGZvciAoY29uc3QgdXNlclNjcmlwdCBvZiBbLi4udXNlclNjcmlwdHNBdFN0YXJ0LCAuLi51c2VyU2NyaXB0c0F0RW5kXSkge1xuICAgICAgICAgICAgICAgIGxldCBpZlN0YXRlbWVudCA9IFwiaWYgKFwiO1xuICAgICAgICAgICAgICAgIGxldCBzb3VyY2UgPSB1c2VyU2NyaXB0LnNvdXJjZTtcbiAgICAgICAgICAgICAgICBpZiAodXNlclNjcmlwdC5hbGxvd2VkT3JpZ2luUnVsZXMgIT0gbnVsbCAmJiAhdXNlclNjcmlwdC5hbGxvd2VkT3JpZ2luUnVsZXMuaW5jbHVkZXMoXCIqXCIpKSB7XG4gICAgICAgICAgICAgICAgICBpZiAodXNlclNjcmlwdC5hbGxvd2VkT3JpZ2luUnVsZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHJldHVybiBlbXB0eSBzb3VyY2Ugc3RyaW5nIGlmIGFsbG93ZWRPcmlnaW5SdWxlcyBpcyBhbiBlbXB0eSBsaXN0LlxuICAgICAgICAgICAgICAgICAgICAvLyBhbiBlbXB0eSBsaXN0IG1lYW5zIHRoYXQgdGhpcyBVc2VyU2NyaXB0IGlzIG5vdCBhbGxvd2VkIGZvciBhbnkgb3JpZ2luLlxuICAgICAgICAgICAgICAgICAgICBzb3VyY2UgPSBcIlwiO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgbGV0IGpzUmVnRXhwQXJyYXkgPSBcIltcIjtcbiAgICAgICAgICAgICAgICAgIGZvciAoY29uc3QgYWxsb3dlZE9yaWdpblJ1bGUgb2YgdXNlclNjcmlwdC5hbGxvd2VkT3JpZ2luUnVsZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGpzUmVnRXhwQXJyYXkubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgICAgICAgICAgIGpzUmVnRXhwQXJyYXkgKz0gXCIsXCI7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAganNSZWdFeHBBcnJheSArPSBgbmV3IFJlZ0V4cCgnJHthbGxvd2VkT3JpZ2luUnVsZS5yZXBsYWNlKFwiXFwnXCIsIFwiXFxcXCdcIil9JylgO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgaWYgKGpzUmVnRXhwQXJyYXkubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgICAgICAgICBqc1JlZ0V4cEFycmF5ICs9IFwiXVwiO1xuICAgICAgICAgICAgICAgICAgICBpZlN0YXRlbWVudCArPSBgJHtqc1JlZ0V4cEFycmF5fS5zb21lKGZ1bmN0aW9uKHJ4KSB7IHJldHVybiByeC50ZXN0KHdpbmRvdy5sb2NhdGlvbi5vcmlnaW4pOyB9KWA7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHdlYlZpZXcuZXZhbHVhdGVKYXZhc2NyaXB0KGlmU3RhdGVtZW50Lmxlbmd0aCA+IDQgPyBgJHtpZlN0YXRlbWVudH0pIHsgJHtzb3VyY2V9IH1gIDogc291cmNlKTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIGxldCB1cmwgPSBpZnJhbWUuc3JjO1xuICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIHVybCA9IGlmcmFtZS5jb250ZW50V2luZG93LmxvY2F0aW9uLmhyZWY7XG4gICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhlKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBfbmF0aXZlQ29tbXVuaWNhdGlvbignb25Mb2FkU3RhcnQnLCB2aWV3SWQsIFt1cmxdKTtcblxuICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGNvbnN0IG9sZExvZ3MgPSB7XG4gICAgICAgICAgICAgICAgICAnbG9nJzogaWZyYW1lLmNvbnRlbnRXaW5kb3cuY29uc29sZS5sb2csXG4gICAgICAgICAgICAgICAgICAnZGVidWcnOiBpZnJhbWUuY29udGVudFdpbmRvdy5jb25zb2xlLmRlYnVnLFxuICAgICAgICAgICAgICAgICAgJ2Vycm9yJzogaWZyYW1lLmNvbnRlbnRXaW5kb3cuY29uc29sZS5lcnJvcixcbiAgICAgICAgICAgICAgICAgICdpbmZvJzogaWZyYW1lLmNvbnRlbnRXaW5kb3cuY29uc29sZS5pbmZvLFxuICAgICAgICAgICAgICAgICAgJ3dhcm4nOiBpZnJhbWUuY29udGVudFdpbmRvdy5jb25zb2xlLndhcm5cbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGZvciAoY29uc3QgayBpbiBvbGRMb2dzKSB7XG4gICAgICAgICAgICAgICAgICAoZnVuY3Rpb24gKG9sZExvZykge1xuICAgICAgICAgICAgICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgICAgICAgICAgICAgIGlmcmFtZS5jb250ZW50V2luZG93LmNvbnNvbGVbb2xkTG9nXSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICB2YXIgbWVzc2FnZSA9ICcnO1xuICAgICAgICAgICAgICAgICAgICAgIGZvciAodmFyIGkgaW4gYXJndW1lbnRzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAobWVzc2FnZSA9PSAnJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlICs9IGFyZ3VtZW50c1tpXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgKz0gJyAnICsgYXJndW1lbnRzW2ldO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgICAgICAgICAgICAgICAgb2xkTG9nc1tvbGRMb2ddLmNhbGwoaWZyYW1lLmNvbnRlbnRXaW5kb3cuY29uc29sZSwgLi4uYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICBfbmF0aXZlQ29tbXVuaWNhdGlvbignb25Db25zb2xlTWVzc2FnZScsIHZpZXdJZCwgW29sZExvZywgbWVzc2FnZV0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9KShrKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhlKTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgY29uc3Qgb3JpZ2luYWxQdXNoU3RhdGUgPSBpZnJhbWUuY29udGVudFdpbmRvdy5oaXN0b3J5LnB1c2hTdGF0ZTtcbiAgICAgICAgICAgICAgICBpZnJhbWUuY29udGVudFdpbmRvdy5oaXN0b3J5LnB1c2hTdGF0ZSA9IGZ1bmN0aW9uIChzdGF0ZSwgdW51c2VkLCB1cmwpIHtcbiAgICAgICAgICAgICAgICAgIG9yaWdpbmFsUHVzaFN0YXRlLmNhbGwoaWZyYW1lLmNvbnRlbnRXaW5kb3chLmhpc3RvcnksIHN0YXRlLCB1bnVzZWQsIHVybCk7XG4gICAgICAgICAgICAgICAgICBsZXQgaWZyYW1lVXJsID0gaWZyYW1lLnNyYztcbiAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGlmcmFtZVVybCA9IGlmcmFtZS5jb250ZW50V2luZG93IS5sb2NhdGlvbi5ocmVmO1xuICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhlKTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIF9uYXRpdmVDb21tdW5pY2F0aW9uKCdvblVwZGF0ZVZpc2l0ZWRIaXN0b3J5Jywgdmlld0lkLCBbaWZyYW1lVXJsXSk7XG4gICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgIGNvbnN0IG9yaWdpbmFsUmVwbGFjZVN0YXRlID0gaWZyYW1lLmNvbnRlbnRXaW5kb3cuaGlzdG9yeS5yZXBsYWNlU3RhdGU7XG4gICAgICAgICAgICAgICAgaWZyYW1lLmNvbnRlbnRXaW5kb3cuaGlzdG9yeS5yZXBsYWNlU3RhdGUgPSBmdW5jdGlvbiAoc3RhdGUsIHVudXNlZCwgdXJsKSB7XG4gICAgICAgICAgICAgICAgICBvcmlnaW5hbFJlcGxhY2VTdGF0ZS5jYWxsKGlmcmFtZS5jb250ZW50V2luZG93IS5oaXN0b3J5LCBzdGF0ZSwgdW51c2VkLCB1cmwpO1xuICAgICAgICAgICAgICAgICAgbGV0IGlmcmFtZVVybCA9IGlmcmFtZS5zcmM7XG4gICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICBpZnJhbWVVcmwgPSBpZnJhbWUuY29udGVudFdpbmRvdyEubG9jYXRpb24uaHJlZjtcbiAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coZSk7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICBfbmF0aXZlQ29tbXVuaWNhdGlvbignb25VcGRhdGVWaXNpdGVkSGlzdG9yeScsIHZpZXdJZCwgW2lmcmFtZVVybF0pO1xuICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICBjb25zdCBvcmlnaW5hbENsb3NlID0gaWZyYW1lLmNvbnRlbnRXaW5kb3cuY2xvc2U7XG4gICAgICAgICAgICAgICAgaWZyYW1lLmNvbnRlbnRXaW5kb3cuY2xvc2UgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICBvcmlnaW5hbENsb3NlLmNhbGwoaWZyYW1lLmNvbnRlbnRXaW5kb3cpO1xuICAgICAgICAgICAgICAgICAgX25hdGl2ZUNvbW11bmljYXRpb24oJ29uQ2xvc2VXaW5kb3cnLCB2aWV3SWQpO1xuICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICBjb25zdCBvcmlnaW5hbE9wZW4gPSBpZnJhbWUuY29udGVudFdpbmRvdy5vcGVuO1xuICAgICAgICAgICAgICAgIGlmcmFtZS5jb250ZW50V2luZG93Lm9wZW4gPSBmdW5jdGlvbiAodXJsLCB0YXJnZXQsIHdpbmRvd0ZlYXR1cmVzKSB7XG4gICAgICAgICAgICAgICAgICBjb25zdCBuZXdXaW5kb3cgPSBvcmlnaW5hbE9wZW4uY2FsbChpZnJhbWUuY29udGVudFdpbmRvdywgLi4uYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgIF9uYXRpdmVDb21tdW5pY2F0aW9uPFByb21pc2U8Ym9vbGVhbj4+KCdvbkNyZWF0ZVdpbmRvdycsIHZpZXdJZCwgW3VybCwgdGFyZ2V0LCB3aW5kb3dGZWF0dXJlc10pLnRoZW4oZnVuY3Rpb24gKGhhbmRsZWRCeUNsaWVudCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoaGFuZGxlZEJ5Q2xpZW50KSB7XG4gICAgICAgICAgICAgICAgICAgICAgbmV3V2luZG93Py5jbG9zZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgIHJldHVybiBuZXdXaW5kb3c7XG4gICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgIGNvbnN0IG9yaWdpbmFsUHJpbnQgPSBpZnJhbWUuY29udGVudFdpbmRvdy5wcmludDtcbiAgICAgICAgICAgICAgICBpZnJhbWUuY29udGVudFdpbmRvdy5wcmludCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgIGxldCBpZnJhbWVVcmwgPSBpZnJhbWUuc3JjO1xuICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgaWZyYW1lVXJsID0gaWZyYW1lLmNvbnRlbnRXaW5kb3chLmxvY2F0aW9uLmhyZWY7XG4gICAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGUpO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgX25hdGl2ZUNvbW11bmljYXRpb24oJ29uUHJpbnRSZXF1ZXN0Jywgdmlld0lkLCBbaWZyYW1lVXJsXSk7XG4gICAgICAgICAgICAgICAgICBvcmlnaW5hbFByaW50LmNhbGwoaWZyYW1lLmNvbnRlbnRXaW5kb3cpO1xuICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICB3ZWJWaWV3LmZ1bmN0aW9uTWFwID0ge1xuICAgICAgICAgICAgICAgICAgXCJ3aW5kb3cub3BlblwiOiBpZnJhbWUuY29udGVudFdpbmRvdy5vcGVuLFxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGNvbnN0IGluaXRpYWxUaXRsZSA9IGlmcmFtZS5jb250ZW50RG9jdW1lbnQ/LnRpdGxlO1xuICAgICAgICAgICAgICAgIGNvbnN0IHRpdGxlRWwgPSBpZnJhbWUuY29udGVudERvY3VtZW50Py5xdWVyeVNlbGVjdG9yKCd0aXRsZScpO1xuICAgICAgICAgICAgICAgIHdlYlZpZXcuZG9jdW1lbnRUaXRsZSA9IGluaXRpYWxUaXRsZTtcbiAgICAgICAgICAgICAgICBfbmF0aXZlQ29tbXVuaWNhdGlvbignb25UaXRsZUNoYW5nZWQnLCB2aWV3SWQsIFtpbml0aWFsVGl0bGVdKTtcbiAgICAgICAgICAgICAgICBpZiAodGl0bGVFbCAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICBuZXcgTXV0YXRpb25PYnNlcnZlcihmdW5jdGlvbiAobXV0YXRpb25zKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHRpdGxlID0gKG11dGF0aW9uc1swXS50YXJnZXQgYXMgSFRNTEVsZW1lbnQpLmlubmVyVGV4dDtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRpdGxlICE9IHdlYlZpZXcuZG9jdW1lbnRUaXRsZSkge1xuICAgICAgICAgICAgICAgICAgICAgIHdlYlZpZXcuZG9jdW1lbnRUaXRsZSA9IHRpdGxlO1xuICAgICAgICAgICAgICAgICAgICAgIF9uYXRpdmVDb21tdW5pY2F0aW9uKCdvblRpdGxlQ2hhbmdlZCcsIHZpZXdJZCwgW3RpdGxlXSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIH0pLm9ic2VydmUoXG4gICAgICAgICAgICAgICAgICAgICAgdGl0bGVFbCxcbiAgICAgICAgICAgICAgICAgICAgICB7c3VidHJlZTogdHJ1ZSwgY2hhcmFjdGVyRGF0YTogdHJ1ZSwgY2hpbGRMaXN0OiB0cnVlfVxuICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBsZXQgb2xkUGl4ZWxSYXRpbyA9IGlmcmFtZS5jb250ZW50V2luZG93LmRldmljZVBpeGVsUmF0aW87XG4gICAgICAgICAgICAgICAgaWZyYW1lLmNvbnRlbnRXaW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigncmVzaXplJywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IG5ld1BpeGVsUmF0aW8gPSBpZnJhbWUuY29udGVudFdpbmRvdyEuZGV2aWNlUGl4ZWxSYXRpbztcbiAgICAgICAgICAgICAgICAgIGlmIChuZXdQaXhlbFJhdGlvICE9PSBvbGRQaXhlbFJhdGlvKSB7XG4gICAgICAgICAgICAgICAgICAgIF9uYXRpdmVDb21tdW5pY2F0aW9uKCdvblpvb21TY2FsZUNoYW5nZWQnLCB2aWV3SWQsIFtvbGRQaXhlbFJhdGlvLCBuZXdQaXhlbFJhdGlvXSk7XG4gICAgICAgICAgICAgICAgICAgIG9sZFBpeGVsUmF0aW8gPSBuZXdQaXhlbFJhdGlvO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgaWZyYW1lLmNvbnRlbnRXaW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigncG9wc3RhdGUnLCBmdW5jdGlvbiAoZXZlbnQ6IEV2ZW50KSB7XG4gICAgICAgICAgICAgICAgICBsZXQgaWZyYW1lVXJsID0gaWZyYW1lLnNyYztcbiAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGlmcmFtZVVybCA9IGlmcmFtZS5jb250ZW50V2luZG93IS5sb2NhdGlvbi5ocmVmO1xuICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhlKTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIF9uYXRpdmVDb21tdW5pY2F0aW9uKCdvblVwZGF0ZVZpc2l0ZWRIaXN0b3J5Jywgdmlld0lkLCBbaWZyYW1lVXJsXSk7XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICBpZnJhbWUuY29udGVudFdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdzY3JvbGwnLCBmdW5jdGlvbiAoZXZlbnQ6IEV2ZW50KSB7XG4gICAgICAgICAgICAgICAgICBsZXQgeCA9IDA7XG4gICAgICAgICAgICAgICAgICBsZXQgeSA9IDA7XG4gICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICB4ID0gaWZyYW1lLmNvbnRlbnRXaW5kb3chLnNjcm9sbFg7XG4gICAgICAgICAgICAgICAgICAgIHkgPSBpZnJhbWUuY29udGVudFdpbmRvdyEuc2Nyb2xsWTtcbiAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coZSk7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICBfbmF0aXZlQ29tbXVuaWNhdGlvbignb25TY3JvbGxDaGFuZ2VkJywgdmlld0lkLCBbeCwgeV0pO1xuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgaWZyYW1lLmNvbnRlbnRXaW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignZm9jdXMnLCBmdW5jdGlvbiAoZXZlbnQ6IEV2ZW50KSB7XG4gICAgICAgICAgICAgICAgICBfbmF0aXZlQ29tbXVuaWNhdGlvbignb25XaW5kb3dGb2N1cycsIHZpZXdJZCk7XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICBpZnJhbWUuY29udGVudFdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdibHVyJywgZnVuY3Rpb24gKGV2ZW50OiBFdmVudCkge1xuICAgICAgICAgICAgICAgICAgX25hdGl2ZUNvbW11bmljYXRpb24oJ29uV2luZG93Qmx1cicsIHZpZXdJZCk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhlKTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgaWYgKCF3ZWJWaWV3LnNldHRpbmdzLmphdmFTY3JpcHRDYW5PcGVuV2luZG93c0F1dG9tYXRpY2FsbHkpIHtcbiAgICAgICAgICAgICAgICAgIGlmcmFtZS5jb250ZW50V2luZG93Lm9wZW4gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignSmF2YVNjcmlwdCBjYW5ub3Qgb3BlbiB3aW5kb3dzIGF1dG9tYXRpY2FsbHknKTtcbiAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKCF3ZWJWaWV3LnNldHRpbmdzLnZlcnRpY2FsU2Nyb2xsQmFyRW5hYmxlZCAmJiAhd2ViVmlldy5zZXR0aW5ncy5ob3Jpem9udGFsU2Nyb2xsQmFyRW5hYmxlZCkge1xuICAgICAgICAgICAgICAgICAgY29uc3Qgc3R5bGUgPSBpZnJhbWUuY29udGVudERvY3VtZW50Py5jcmVhdGVFbGVtZW50KCdzdHlsZScpO1xuICAgICAgICAgICAgICAgICAgaWYgKHN0eWxlICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgICAgICAgc3R5bGUuaWQgPSBcInNldHRpbmdzLnZlcnRpY2FsU2Nyb2xsQmFyRW5hYmxlZC1zZXR0aW5ncy5ob3Jpem9udGFsU2Nyb2xsQmFyRW5hYmxlZFwiO1xuICAgICAgICAgICAgICAgICAgICBzdHlsZS5pbm5lckhUTUwgPSBcImJvZHk6Oi13ZWJraXQtc2Nyb2xsYmFyIHsgd2lkdGg6IDBweDsgaGVpZ2h0OiAwcHg7IH1cIjtcbiAgICAgICAgICAgICAgICAgICAgaWZyYW1lLmNvbnRlbnREb2N1bWVudD8uaGVhZC5hcHBlbmQoc3R5bGUpO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICh3ZWJWaWV3LnNldHRpbmdzLmRpc2FibGVWZXJ0aWNhbFNjcm9sbCkge1xuICAgICAgICAgICAgICAgICAgY29uc3Qgc3R5bGUgPSBpZnJhbWUuY29udGVudERvY3VtZW50Py5jcmVhdGVFbGVtZW50KCdzdHlsZScpO1xuICAgICAgICAgICAgICAgICAgaWYgKHN0eWxlICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgICAgICAgc3R5bGUuaWQgPSBcInNldHRpbmdzLmRpc2FibGVWZXJ0aWNhbFNjcm9sbFwiO1xuICAgICAgICAgICAgICAgICAgICBzdHlsZS5pbm5lckhUTUwgPSBcImJvZHkgeyBvdmVyZmxvdy15OiBoaWRkZW47IH1cIjtcbiAgICAgICAgICAgICAgICAgICAgaWZyYW1lLmNvbnRlbnREb2N1bWVudD8uaGVhZC5hcHBlbmQoc3R5bGUpO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICh3ZWJWaWV3LnNldHRpbmdzLmRpc2FibGVIb3Jpem9udGFsU2Nyb2xsKSB7XG4gICAgICAgICAgICAgICAgICBjb25zdCBzdHlsZSA9IGlmcmFtZS5jb250ZW50RG9jdW1lbnQ/LmNyZWF0ZUVsZW1lbnQoJ3N0eWxlJyk7XG4gICAgICAgICAgICAgICAgICBpZiAoc3R5bGUgIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICBzdHlsZS5pZCA9IFwic2V0dGluZ3MuZGlzYWJsZUhvcml6b250YWxTY3JvbGxcIjtcbiAgICAgICAgICAgICAgICAgICAgc3R5bGUuaW5uZXJIVE1MID0gXCJib2R5IHsgb3ZlcmZsb3cteDogaGlkZGVuOyB9XCI7XG4gICAgICAgICAgICAgICAgICAgIGlmcmFtZS5jb250ZW50RG9jdW1lbnQ/LmhlYWQuYXBwZW5kKHN0eWxlKTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAod2ViVmlldy5zZXR0aW5ncy5kaXNhYmxlQ29udGV4dE1lbnUpIHtcbiAgICAgICAgICAgICAgICAgIGlmcmFtZS5jb250ZW50V2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ2NvbnRleHRtZW51Jywgd2ViVmlldy5kaXNhYmxlQ29udGV4dE1lbnVIYW5kbGVyKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhlKTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIF9uYXRpdmVDb21tdW5pY2F0aW9uKCdvbkxvYWRTdG9wJywgdmlld0lkLCBbdXJsXSk7XG5cbiAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBpZnJhbWUuY29udGVudFdpbmRvdy5kaXNwYXRjaEV2ZW50KG5ldyBFdmVudCgnZmx1dHRlckluQXBwV2ViVmlld1BsYXRmb3JtUmVhZHknKSk7XG4gICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhlKTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHNldFNldHRpbmdzOiBmdW5jdGlvbiAobmV3U2V0dGluZ3M6IEluQXBwV2ViVmlld1NldHRpbmdzKSB7XG4gICAgICAgICAgY29uc3QgaWZyYW1lID0gd2ViVmlldy5pZnJhbWU7XG4gICAgICAgICAgaWYgKGlmcmFtZSA9PSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBpZiAod2ViVmlldy5zZXR0aW5ncy5qYXZhU2NyaXB0Q2FuT3BlbldpbmRvd3NBdXRvbWF0aWNhbGx5ICE9IG5ld1NldHRpbmdzLmphdmFTY3JpcHRDYW5PcGVuV2luZG93c0F1dG9tYXRpY2FsbHkpIHtcbiAgICAgICAgICAgICAgaWYgKCFuZXdTZXR0aW5ncy5qYXZhU2NyaXB0Q2FuT3BlbldpbmRvd3NBdXRvbWF0aWNhbGx5KSB7XG4gICAgICAgICAgICAgICAgaWZyYW1lLmNvbnRlbnRXaW5kb3chLm9wZW4gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0phdmFTY3JpcHQgY2Fubm90IG9wZW4gd2luZG93cyBhdXRvbWF0aWNhbGx5Jyk7XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZnJhbWUuY29udGVudFdpbmRvdyEub3BlbiA9IHdlYlZpZXcuZnVuY3Rpb25NYXBbXCJ3aW5kb3cub3BlblwiXTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAod2ViVmlldy5zZXR0aW5ncy52ZXJ0aWNhbFNjcm9sbEJhckVuYWJsZWQgIT0gbmV3U2V0dGluZ3MudmVydGljYWxTY3JvbGxCYXJFbmFibGVkICYmXG4gICAgICAgICAgICAgICAgd2ViVmlldy5zZXR0aW5ncy5ob3Jpem9udGFsU2Nyb2xsQmFyRW5hYmxlZCAhPSBuZXdTZXR0aW5ncy5ob3Jpem9udGFsU2Nyb2xsQmFyRW5hYmxlZCkge1xuICAgICAgICAgICAgICBpZiAoIW5ld1NldHRpbmdzLnZlcnRpY2FsU2Nyb2xsQmFyRW5hYmxlZCAmJiAhbmV3U2V0dGluZ3MuaG9yaXpvbnRhbFNjcm9sbEJhckVuYWJsZWQpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBzdHlsZSA9IGlmcmFtZS5jb250ZW50RG9jdW1lbnQ/LmNyZWF0ZUVsZW1lbnQoJ3N0eWxlJyk7XG4gICAgICAgICAgICAgICAgaWYgKHN0eWxlICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgICAgIHN0eWxlLmlkID0gXCJzZXR0aW5ncy52ZXJ0aWNhbFNjcm9sbEJhckVuYWJsZWQtc2V0dGluZ3MuaG9yaXpvbnRhbFNjcm9sbEJhckVuYWJsZWRcIjtcbiAgICAgICAgICAgICAgICAgIHN0eWxlLmlubmVySFRNTCA9IFwiYm9keTo6LXdlYmtpdC1zY3JvbGxiYXIgeyB3aWR0aDogMHB4OyBoZWlnaHQ6IDBweDsgfVwiO1xuICAgICAgICAgICAgICAgICAgaWZyYW1lLmNvbnRlbnREb2N1bWVudD8uaGVhZC5hcHBlbmQoc3R5bGUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjb25zdCBzdHlsZUVsZW1lbnQgPSBpZnJhbWUuY29udGVudERvY3VtZW50Py5nZXRFbGVtZW50QnlJZChcInNldHRpbmdzLnZlcnRpY2FsU2Nyb2xsQmFyRW5hYmxlZC1zZXR0aW5ncy5ob3Jpem9udGFsU2Nyb2xsQmFyRW5hYmxlZFwiKTtcbiAgICAgICAgICAgICAgICBpZiAoc3R5bGVFbGVtZW50KSB7XG4gICAgICAgICAgICAgICAgICBzdHlsZUVsZW1lbnQucmVtb3ZlKClcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHdlYlZpZXcuc2V0dGluZ3MuZGlzYWJsZVZlcnRpY2FsU2Nyb2xsICE9IG5ld1NldHRpbmdzLmRpc2FibGVWZXJ0aWNhbFNjcm9sbCkge1xuICAgICAgICAgICAgICBpZiAobmV3U2V0dGluZ3MuZGlzYWJsZVZlcnRpY2FsU2Nyb2xsKSB7XG4gICAgICAgICAgICAgICAgY29uc3Qgc3R5bGUgPSBpZnJhbWUuY29udGVudERvY3VtZW50Py5jcmVhdGVFbGVtZW50KCdzdHlsZScpO1xuICAgICAgICAgICAgICAgIGlmIChzdHlsZSAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICBzdHlsZS5pZCA9IFwic2V0dGluZ3MuZGlzYWJsZVZlcnRpY2FsU2Nyb2xsXCI7XG4gICAgICAgICAgICAgICAgICBzdHlsZS5pbm5lckhUTUwgPSBcImJvZHkgeyBvdmVyZmxvdy15OiBoaWRkZW47IH1cIjtcbiAgICAgICAgICAgICAgICAgIGlmcmFtZS5jb250ZW50RG9jdW1lbnQ/LmhlYWQuYXBwZW5kKHN0eWxlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc3Qgc3R5bGVFbGVtZW50ID0gaWZyYW1lLmNvbnRlbnREb2N1bWVudD8uZ2V0RWxlbWVudEJ5SWQoXCJzZXR0aW5ncy5kaXNhYmxlVmVydGljYWxTY3JvbGxcIik7XG4gICAgICAgICAgICAgICAgaWYgKHN0eWxlRWxlbWVudCkge1xuICAgICAgICAgICAgICAgICAgc3R5bGVFbGVtZW50LnJlbW92ZSgpXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh3ZWJWaWV3LnNldHRpbmdzLmRpc2FibGVIb3Jpem9udGFsU2Nyb2xsICE9IG5ld1NldHRpbmdzLmRpc2FibGVIb3Jpem9udGFsU2Nyb2xsKSB7XG4gICAgICAgICAgICAgIGlmIChuZXdTZXR0aW5ncy5kaXNhYmxlSG9yaXpvbnRhbFNjcm9sbCkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHN0eWxlID0gaWZyYW1lLmNvbnRlbnREb2N1bWVudD8uY3JlYXRlRWxlbWVudCgnc3R5bGUnKTtcbiAgICAgICAgICAgICAgICBpZiAoc3R5bGUgIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgc3R5bGUuaWQgPSBcInNldHRpbmdzLmRpc2FibGVIb3Jpem9udGFsU2Nyb2xsXCI7XG4gICAgICAgICAgICAgICAgICBzdHlsZS5pbm5lckhUTUwgPSBcImJvZHkgeyBvdmVyZmxvdy14OiBoaWRkZW47IH1cIjtcbiAgICAgICAgICAgICAgICAgIGlmcmFtZS5jb250ZW50RG9jdW1lbnQ/LmhlYWQuYXBwZW5kKHN0eWxlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc3Qgc3R5bGVFbGVtZW50ID0gaWZyYW1lLmNvbnRlbnREb2N1bWVudD8uZ2V0RWxlbWVudEJ5SWQoXCJzZXR0aW5ncy5kaXNhYmxlSG9yaXpvbnRhbFNjcm9sbFwiKTtcbiAgICAgICAgICAgICAgICBpZiAoc3R5bGVFbGVtZW50KSB7XG4gICAgICAgICAgICAgICAgICBzdHlsZUVsZW1lbnQucmVtb3ZlKClcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHdlYlZpZXcuc2V0dGluZ3MuZGlzYWJsZUNvbnRleHRNZW51ICE9IG5ld1NldHRpbmdzLmRpc2FibGVDb250ZXh0TWVudSkge1xuICAgICAgICAgICAgICBpZiAobmV3U2V0dGluZ3MuZGlzYWJsZUNvbnRleHRNZW51KSB7XG4gICAgICAgICAgICAgICAgaWZyYW1lLmNvbnRlbnRXaW5kb3c/LmFkZEV2ZW50TGlzdGVuZXIoJ2NvbnRleHRtZW51Jywgd2ViVmlldy5kaXNhYmxlQ29udGV4dE1lbnVIYW5kbGVyKTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZnJhbWUuY29udGVudFdpbmRvdz8ucmVtb3ZlRXZlbnRMaXN0ZW5lcignY29udGV4dG1lbnUnLCB3ZWJWaWV3LmRpc2FibGVDb250ZXh0TWVudUhhbmRsZXIpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5sb2coZSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgd2ViVmlldy5zZXR0aW5ncyA9IG5ld1NldHRpbmdzO1xuICAgICAgICB9LFxuICAgICAgICByZWxvYWQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICB2YXIgaWZyYW1lID0gd2ViVmlldy5pZnJhbWU7XG4gICAgICAgICAgaWYgKGlmcmFtZSAhPSBudWxsICYmIGlmcmFtZS5jb250ZW50V2luZG93ICE9IG51bGwpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgIGlmcmFtZS5jb250ZW50V2luZG93LmxvY2F0aW9uLnJlbG9hZCgpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICBjb25zb2xlLmxvZyhlKTtcbiAgICAgICAgICAgICAgaWZyYW1lLmNvbnRlbnRXaW5kb3cubG9jYXRpb24uaHJlZiA9IGlmcmFtZS5zcmM7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBnb0JhY2s6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICB2YXIgaWZyYW1lID0gd2ViVmlldy5pZnJhbWU7XG4gICAgICAgICAgaWYgKGlmcmFtZSAhPSBudWxsKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICBpZnJhbWUuY29udGVudFdpbmRvdz8uaGlzdG9yeS5iYWNrKCk7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgIGNvbnNvbGUubG9nKGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgZ29Gb3J3YXJkOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgdmFyIGlmcmFtZSA9IHdlYlZpZXcuaWZyYW1lO1xuICAgICAgICAgIGlmIChpZnJhbWUgIT0gbnVsbCkge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgaWZyYW1lLmNvbnRlbnRXaW5kb3c/Lmhpc3RvcnkuZm9yd2FyZCgpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICBjb25zb2xlLmxvZyhlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGdvQmFja09yRm9yd2FyZDogZnVuY3Rpb24gKHN0ZXBzKSB7XG4gICAgICAgICAgdmFyIGlmcmFtZSA9IHdlYlZpZXcuaWZyYW1lO1xuICAgICAgICAgIGlmIChpZnJhbWUgIT0gbnVsbCkge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgaWZyYW1lLmNvbnRlbnRXaW5kb3c/Lmhpc3RvcnkuZ28oc3RlcHMpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICBjb25zb2xlLmxvZyhlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGV2YWx1YXRlSmF2YXNjcmlwdDogZnVuY3Rpb24gKHNvdXJjZSkge1xuICAgICAgICAgIGNvbnN0IGlmcmFtZSA9IHdlYlZpZXcuaWZyYW1lO1xuICAgICAgICAgIGxldCByZXN1bHQgPSBudWxsO1xuICAgICAgICAgIGlmIChpZnJhbWUgIT0gbnVsbCkge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgcmVzdWx0ID0gSlNPTi5zdHJpbmdpZnkoaWZyYW1lLmNvbnRlbnRXaW5kb3c/LmV2YWwoc291cmNlKSk7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH0sXG4gICAgICAgIHN0b3BMb2FkaW5nOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgY29uc3QgaWZyYW1lID0gd2ViVmlldy5pZnJhbWU7XG4gICAgICAgICAgaWYgKGlmcmFtZSAhPSBudWxsKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICBpZnJhbWUuY29udGVudFdpbmRvdz8uc3RvcCgpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICBjb25zb2xlLmxvZyhlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGdldFVybDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnN0IGlmcmFtZSA9IHdlYlZpZXcuaWZyYW1lO1xuICAgICAgICAgIGxldCB1cmwgPSBpZnJhbWU/LnNyYztcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgdXJsID0gaWZyYW1lPy5jb250ZW50V2luZG93Py5sb2NhdGlvbi5ocmVmO1xuICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gdXJsO1xuICAgICAgICB9LFxuICAgICAgICBnZXRUaXRsZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnN0IGlmcmFtZSA9IHdlYlZpZXcuaWZyYW1lO1xuICAgICAgICAgIGxldCB0aXRsZSA9IG51bGw7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHRpdGxlID0gaWZyYW1lPy5jb250ZW50RG9jdW1lbnQ/LnRpdGxlO1xuICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gdGl0bGU7XG4gICAgICAgIH0sXG4gICAgICAgIGluamVjdEphdmFzY3JpcHRGaWxlRnJvbVVybDogZnVuY3Rpb24gKHVybEZpbGUsIHNjcmlwdEh0bWxUYWdBdHRyaWJ1dGVzKSB7XG4gICAgICAgICAgY29uc3QgaWZyYW1lID0gd2ViVmlldy5pZnJhbWU7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IGQgPSBpZnJhbWU/LmNvbnRlbnREb2N1bWVudDtcbiAgICAgICAgICAgIGlmIChkID09IG51bGwpIHtcbiAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3Qgc2NyaXB0ID0gZC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTtcbiAgICAgICAgICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKHNjcmlwdEh0bWxUYWdBdHRyaWJ1dGVzKSkge1xuICAgICAgICAgICAgICBpZiAoc2NyaXB0SHRtbFRhZ0F0dHJpYnV0ZXNba2V5XSAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgICAgICAgICAgIHNjcmlwdFtrZXldID0gc2NyaXB0SHRtbFRhZ0F0dHJpYnV0ZXNba2V5XTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHNjcmlwdC5pZCAhPSBudWxsKSB7XG4gICAgICAgICAgICAgIHNjcmlwdC5vbmxvYWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgX25hdGl2ZUNvbW11bmljYXRpb24oJ29uSW5qZWN0ZWRTY3JpcHRMb2FkZWQnLCB3ZWJWaWV3LnZpZXdJZCwgW3NjcmlwdC5pZF0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHNjcmlwdC5vbmVycm9yID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIF9uYXRpdmVDb21tdW5pY2F0aW9uKCdvbkluamVjdGVkU2NyaXB0RXJyb3InLCB3ZWJWaWV3LnZpZXdJZCwgW3NjcmlwdC5pZF0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzY3JpcHQuc3JjID0gdXJsRmlsZTtcbiAgICAgICAgICAgIGlmIChkLmJvZHkgIT0gbnVsbCkge1xuICAgICAgICAgICAgICBkLmJvZHkuYXBwZW5kQ2hpbGQoc2NyaXB0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGluamVjdENTU0NvZGU6IGZ1bmN0aW9uIChzb3VyY2UpIHtcbiAgICAgICAgICBjb25zdCBpZnJhbWUgPSB3ZWJWaWV3LmlmcmFtZTtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3QgZCA9IGlmcmFtZT8uY29udGVudERvY3VtZW50O1xuICAgICAgICAgICAgaWYgKGQgPT0gbnVsbCkge1xuICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBzdHlsZSA9IGQuY3JlYXRlRWxlbWVudCgnc3R5bGUnKTtcbiAgICAgICAgICAgIHN0eWxlLmlubmVySFRNTCA9IHNvdXJjZTtcbiAgICAgICAgICAgIGlmIChkLmhlYWQgIT0gbnVsbCkge1xuICAgICAgICAgICAgICBkLmhlYWQuYXBwZW5kQ2hpbGQoc3R5bGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgaW5qZWN0Q1NTRmlsZUZyb21Vcmw6IGZ1bmN0aW9uICh1cmxGaWxlLCBjc3NMaW5rSHRtbFRhZ0F0dHJpYnV0ZXMpIHtcbiAgICAgICAgICBjb25zdCBpZnJhbWUgPSB3ZWJWaWV3LmlmcmFtZTtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3QgZCA9IGlmcmFtZT8uY29udGVudERvY3VtZW50O1xuICAgICAgICAgICAgaWYgKGQgPT0gbnVsbCkge1xuICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBsaW5rID0gZC5jcmVhdGVFbGVtZW50KCdsaW5rJyk7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhjc3NMaW5rSHRtbFRhZ0F0dHJpYnV0ZXMpKSB7XG4gICAgICAgICAgICAgIGlmIChjc3NMaW5rSHRtbFRhZ0F0dHJpYnV0ZXNba2V5XSAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgICAgICAgICAgIGxpbmtba2V5XSA9IGNzc0xpbmtIdG1sVGFnQXR0cmlidXRlc1trZXldO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBsaW5rLnR5cGUgPSAndGV4dC9jc3MnO1xuICAgICAgICAgICAgdmFyIGFsdGVybmF0ZVN0eWxlc2hlZXQgPSBcIlwiO1xuICAgICAgICAgICAgaWYgKGNzc0xpbmtIdG1sVGFnQXR0cmlidXRlcy5hbHRlcm5hdGVTdHlsZXNoZWV0KSB7XG4gICAgICAgICAgICAgIGFsdGVybmF0ZVN0eWxlc2hlZXQgPSBcImFsdGVybmF0ZSBcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxpbmsucmVsID0gYWx0ZXJuYXRlU3R5bGVzaGVldCArIFwic3R5bGVzaGVldFwiO1xuICAgICAgICAgICAgbGluay5ocmVmID0gdXJsRmlsZTtcbiAgICAgICAgICAgIGlmIChkLmhlYWQgIT0gbnVsbCkge1xuICAgICAgICAgICAgICBkLmhlYWQuYXBwZW5kQ2hpbGQobGluayk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5sb2coZSk7XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBzY3JvbGxUbzogZnVuY3Rpb24gKHgsIHksIGFuaW1hdGVkKSB7XG4gICAgICAgICAgY29uc3QgaWZyYW1lID0gd2ViVmlldy5pZnJhbWU7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGlmIChhbmltYXRlZCkge1xuICAgICAgICAgICAgICBpZnJhbWU/LmNvbnRlbnRXaW5kb3c/LnNjcm9sbFRvKHt0b3A6IHksIGxlZnQ6IHgsIGJlaGF2aW9yOiAnc21vb3RoJ30pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgaWZyYW1lPy5jb250ZW50V2luZG93Py5zY3JvbGxUbyh4LCB5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHNjcm9sbEJ5OiBmdW5jdGlvbiAoeCwgeSwgYW5pbWF0ZWQpIHtcbiAgICAgICAgICBjb25zdCBpZnJhbWUgPSB3ZWJWaWV3LmlmcmFtZTtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgaWYgKGFuaW1hdGVkKSB7XG4gICAgICAgICAgICAgIGlmcmFtZT8uY29udGVudFdpbmRvdz8uc2Nyb2xsQnkoe3RvcDogeSwgbGVmdDogeCwgYmVoYXZpb3I6ICdzbW9vdGgnfSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBpZnJhbWU/LmNvbnRlbnRXaW5kb3c/LnNjcm9sbEJ5KHgsIHkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgcHJpbnRDdXJyZW50UGFnZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnN0IGlmcmFtZSA9IHdlYlZpZXcuaWZyYW1lO1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBpZnJhbWU/LmNvbnRlbnRXaW5kb3c/LnByaW50KCk7XG4gICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5sb2coZSk7XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBnZXRDb250ZW50SGVpZ2h0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgY29uc3QgaWZyYW1lID0gd2ViVmlldy5pZnJhbWU7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJldHVybiBpZnJhbWU/LmNvbnRlbnREb2N1bWVudD8uZG9jdW1lbnRFbGVtZW50LnNjcm9sbEhlaWdodDtcbiAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhlKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH0sXG4gICAgICAgIGdldENvbnRlbnRXaWR0aDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnN0IGlmcmFtZSA9IHdlYlZpZXcuaWZyYW1lO1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXR1cm4gaWZyYW1lPy5jb250ZW50RG9jdW1lbnQ/LmRvY3VtZW50RWxlbWVudC5zY3JvbGxXaWR0aDtcbiAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhlKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH0sXG4gICAgICAgIGdldFNlbGVjdGVkVGV4dDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnN0IGlmcmFtZSA9IHdlYlZpZXcuaWZyYW1lO1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBsZXQgdHh0O1xuICAgICAgICAgICAgY29uc3QgdyA9IGlmcmFtZT8uY29udGVudFdpbmRvdztcbiAgICAgICAgICAgIGlmICh3ID09IG51bGwpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAody5nZXRTZWxlY3Rpb24pIHtcbiAgICAgICAgICAgICAgdHh0ID0gdy5nZXRTZWxlY3Rpb24oKT8udG9TdHJpbmcoKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAody5kb2N1bWVudC5nZXRTZWxlY3Rpb24pIHtcbiAgICAgICAgICAgICAgdHh0ID0gdy5kb2N1bWVudC5nZXRTZWxlY3Rpb24oKT8udG9TdHJpbmcoKTtcbiAgICAgICAgICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgICAgICAgfSBlbHNlIGlmICh3LmRvY3VtZW50LnNlbGVjdGlvbikge1xuICAgICAgICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgICAgICAgIHR4dCA9IHcuZG9jdW1lbnQuc2VsZWN0aW9uLmNyZWF0ZVJhbmdlKCkudGV4dDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB0eHQ7XG4gICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5sb2coZSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9LFxuICAgICAgICBnZXRTY3JvbGxYOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgY29uc3QgaWZyYW1lID0gd2ViVmlldy5pZnJhbWU7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJldHVybiBpZnJhbWU/LmNvbnRlbnRXaW5kb3c/LnNjcm9sbFg7XG4gICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5sb2coZSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9LFxuICAgICAgICBnZXRTY3JvbGxZOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgY29uc3QgaWZyYW1lID0gd2ViVmlldy5pZnJhbWU7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJldHVybiBpZnJhbWU/LmNvbnRlbnRXaW5kb3c/LnNjcm9sbFk7XG4gICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5sb2coZSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9LFxuICAgICAgICBpc1NlY3VyZUNvbnRleHQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBjb25zdCBpZnJhbWUgPSB3ZWJWaWV3LmlmcmFtZTtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIGlmcmFtZT8uY29udGVudFdpbmRvdz8uaXNTZWN1cmVDb250ZXh0ID8/IGZhbHNlO1xuICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH0sXG4gICAgICAgIGNhblNjcm9sbFZlcnRpY2FsbHk6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBjb25zdCBpZnJhbWUgPSB3ZWJWaWV3LmlmcmFtZTtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIChpZnJhbWU/LmNvbnRlbnREb2N1bWVudD8uYm9keS5zY3JvbGxIZWlnaHQgPz8gMCkgPiAoaWZyYW1lPy5jb250ZW50V2luZG93Py5pbm5lckhlaWdodCA/PyAwKTtcbiAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhlKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9LFxuICAgICAgICBjYW5TY3JvbGxIb3Jpem9udGFsbHk6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBjb25zdCBpZnJhbWUgPSB3ZWJWaWV3LmlmcmFtZTtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIChpZnJhbWU/LmNvbnRlbnREb2N1bWVudD8uYm9keS5zY3JvbGxXaWR0aCA/PyAwKSA+IChpZnJhbWU/LmNvbnRlbnRXaW5kb3c/LmlubmVyV2lkdGggPz8gMCk7XG4gICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5sb2coZSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfSxcbiAgICAgICAgZ2V0U2l6ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnN0IGlmcmFtZUNvbnRhaW5lciA9IHdlYlZpZXcuaWZyYW1lQ29udGFpbmVyO1xuICAgICAgICAgIGxldCB3aWR0aCA9IDAuMDtcbiAgICAgICAgICBsZXQgaGVpZ2h0ID0gMC4wO1xuICAgICAgICAgIGlmIChpZnJhbWVDb250YWluZXIgIT0gbnVsbCkge1xuICAgICAgICAgICAgaWYgKGlmcmFtZUNvbnRhaW5lci5zdHlsZS53aWR0aCAhPSBudWxsICYmIGlmcmFtZUNvbnRhaW5lci5zdHlsZS53aWR0aCAhPSAnJyAmJiBpZnJhbWVDb250YWluZXIuc3R5bGUud2lkdGguaW5kZXhPZigncHgnKSA+IDApIHtcbiAgICAgICAgICAgICAgd2lkdGggPSBwYXJzZUZsb2F0KGlmcmFtZUNvbnRhaW5lci5zdHlsZS53aWR0aCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAod2lkdGggPT0gbnVsbCB8fCB3aWR0aCA9PSAwLjApIHtcbiAgICAgICAgICAgICAgd2lkdGggPSBpZnJhbWVDb250YWluZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkud2lkdGg7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoaWZyYW1lQ29udGFpbmVyLnN0eWxlLmhlaWdodCAhPSBudWxsICYmIGlmcmFtZUNvbnRhaW5lci5zdHlsZS5oZWlnaHQgIT0gJycgJiYgaWZyYW1lQ29udGFpbmVyLnN0eWxlLmhlaWdodC5pbmRleE9mKCdweCcpID4gMCkge1xuICAgICAgICAgICAgICBoZWlnaHQgPSBwYXJzZUZsb2F0KGlmcmFtZUNvbnRhaW5lci5zdHlsZS5oZWlnaHQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGhlaWdodCA9PSBudWxsIHx8IGhlaWdodCA9PSAwLjApIHtcbiAgICAgICAgICAgICAgaGVpZ2h0ID0gaWZyYW1lQ29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmhlaWdodDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHdpZHRoOiB3aWR0aCxcbiAgICAgICAgICAgIGhlaWdodDogaGVpZ2h0XG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgcmV0dXJuIHdlYlZpZXc7XG4gICAgfSxcbiAgICBnZXRDb29raWVFeHBpcmF0aW9uRGF0ZTogZnVuY3Rpb24gKHRpbWVzdGFtcDogbnVtYmVyKSB7XG4gICAgICByZXR1cm4gKG5ldyBEYXRlKHRpbWVzdGFtcCkpLnRvVVRDU3RyaW5nKCk7XG4gICAgfSxcbiAgICBuYXRpdmVBc3luY0NvbW11bmljYXRpb246IGZ1bmN0aW9uIChtZXRob2Q6IHN0cmluZywgdmlld0lkOiBudW1iZXIgfCBzdHJpbmcsIGFyZ3M/OiBhbnlbXSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTWV0aG9kIG5vdCBpbXBsZW1lbnRlZC5cIik7XG4gICAgfSxcbiAgICBuYXRpdmVTeW5jQ29tbXVuaWNhdGlvbjogZnVuY3Rpb24gKG1ldGhvZDogc3RyaW5nLCB2aWV3SWQ6IG51bWJlciB8IHN0cmluZywgYXJncz86IGFueVtdKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJNZXRob2Qgbm90IGltcGxlbWVudGVkLlwiKTtcbiAgICB9LFxuICAgIG5hdGl2ZUNvbW11bmljYXRpb246IGZ1bmN0aW9uIChtZXRob2Q6IHN0cmluZywgdmlld0lkOiBudW1iZXIgfCBzdHJpbmcsIGFyZ3M/OiBhbnlbXSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gd2luZG93LmZsdXR0ZXJfaW5hcHB3ZWJ2aWV3X3BsdWdpbi5uYXRpdmVTeW5jQ29tbXVuaWNhdGlvbihtZXRob2QsIHZpZXdJZCwgYXJncyk7XG4gICAgICAgIHJldHVybiByZXN1bHQgIT0gbnVsbCA/IEpTT04ucGFyc2UocmVzdWx0KSA6IG51bGw7XG4gICAgICB9IGNhdGNoIChlMSkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHByb21pc2UgPSB3aW5kb3cuZmx1dHRlcl9pbmFwcHdlYnZpZXdfcGx1Z2luLm5hdGl2ZUFzeW5jQ29tbXVuaWNhdGlvbihtZXRob2QsIHZpZXdJZCwgYXJncyk7XG4gICAgICAgICAgcmV0dXJuIHByb21pc2UudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0ICE9IG51bGwgPyBKU09OLnBhcnNlKHJlc3VsdCkgOiBudWxsO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChlMikge1xuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcbiAgfTtcblxuICBsZXQgX25hdGl2ZUNvbW11bmljYXRpb24gPSB3aW5kb3cuZmx1dHRlcl9pbmFwcHdlYnZpZXdfcGx1Z2luLm5hdGl2ZUNvbW11bmljYXRpb247XG59KSgpOyJdLAogICJtYXBwaW5ncyI6ICI7Q0FtQkMsV0FBWTtBQUNYLE1BQUksa0JBQWtCLE9BQU8sS0FBSztBQUNsQyxNQUFJLGVBQWUsT0FBTyxNQUFNLFVBQVU7QUFDMUMsZUFBYSxPQUFPLE9BQU8sU0FBUyxVQUFVO0FBRTlDLFNBQU8sOEJBQThCO0FBQUEsSUFDbkMsMkJBQTJCLFNBQVUsUUFBeUIsUUFBMkIsaUJBQWlDLGNBQXNCO0FBQzlJLFlBQU0sV0FBVyxPQUFPO0FBQ3hCLFlBQU0sVUFBd0I7QUFBQSxRQUM1QjtBQUFBLFFBQ0E7QUFBQSxRQUNBLFFBQVE7QUFBQSxRQUNSLGlCQUFpQjtBQUFBLFFBQ2pCLGNBQWM7QUFBQSxRQUNkLGVBQWU7QUFBQSxRQUNmLGFBQWEsQ0FBQztBQUFBLFFBQ2QsVUFBVSxDQUFDO0FBQUEsUUFDWCx5QkFBeUI7QUFBQSxRQUN6QiwyQkFBMkIsU0FBVSxPQUFjO0FBQ2pELGdCQUFNLGVBQWU7QUFDckIsZ0JBQU0sZ0JBQWdCO0FBQ3RCLGlCQUFPO0FBQUEsUUFDVDtBQUFBLFFBQ0EsU0FBUyxTQUFVLFVBQWdDO0FBQ2pELGtCQUFRLFdBQVc7QUFFbkIsa0JBQVEsMEJBQTBCLFFBQVEsU0FBUywyQkFBMkI7QUFDOUUsZ0JBQU0sa0NBQWtDLFFBQVEsU0FBUztBQUN6RCxjQUFJLG1DQUFtQyxRQUFRLENBQUMsZ0NBQWdDLFNBQVMsR0FBRyxHQUFHO0FBQzdGLGdCQUFJLGdDQUFnQyxXQUFXLEdBQUc7QUFFaEQsc0JBQVEsMEJBQTBCO0FBQUEsWUFDcEM7QUFBQSxVQUNGO0FBRUEsbUJBQVMsaUJBQWlCLG9CQUFvQixTQUFVLE9BQWM7QUFJcEUsZ0JBQUksU0FBUyxxQkFBcUIsU0FBUyxrQkFBa0IsTUFBTSxVQUFVO0FBQzNFLHNCQUFRLGVBQWU7QUFDdkIsbUNBQXFCLHFCQUFxQixNQUFNO0FBQUEsWUFDbEQsV0FBVyxDQUFDLFNBQVMscUJBQXFCLFFBQVEsY0FBYztBQUM5RCxzQkFBUSxlQUFlO0FBQ3ZCLG1DQUFxQixvQkFBb0IsTUFBTTtBQUFBLFlBQ2pELE9BQU87QUFDTCxzQkFBUSxlQUFlO0FBQUEsWUFDekI7QUFBQSxVQUNGLENBQUM7QUFFRCxjQUFJLFVBQVUsTUFBTTtBQUNsQixvQkFBUSxTQUFTO0FBQ2pCLG9CQUFRLGtCQUFrQjtBQUMxQixtQkFBTyxpQkFBaUIsUUFBUSxTQUFVLE9BQWM7QUFDdEQsa0JBQUksT0FBTyxpQkFBaUIsTUFBTTtBQUNoQztBQUFBLGNBQ0Y7QUFFQSxvQkFBTSxxQkFBcUIscUJBQW1DLHdCQUF3QixRQUFRLDBCQUEwQyxDQUFDO0FBQ3pJLG9CQUFNLG1CQUFtQixxQkFBbUMsd0JBQXdCLFFBQVEsd0JBQXdDLENBQUM7QUFFckksa0JBQUk7QUFDRixvQkFBSSwwQkFBMEIsUUFBUTtBQUN0QyxvQkFBSSxtQ0FBbUMsTUFBTTtBQUMzQyw0Q0FBMEIsZ0NBQ3JCLElBQUksdUJBQXFCLElBQUksT0FBTyxpQkFBaUIsQ0FBQyxFQUN0RCxLQUFLLENBQUMsT0FBTztBQUNaLDJCQUFPLEdBQUcsS0FBSyxPQUFPLGNBQWUsU0FBUyxNQUFNO0FBQUEsa0JBQ3RELENBQUM7QUFBQSxnQkFDUDtBQUNBLG9CQUFJLHlCQUF5QjtBQUMzQix3QkFBTSx1QkFBdUIscUJBQTZCLDJCQUEyQixNQUFNO0FBRTNGLHlCQUFPLGNBQWUsb0JBQW9CLElBQUk7QUFBQSxvQkFDNUMsYUFBYSxXQUFZO0FBQ3ZCLDBCQUFJLFNBQVM7QUFDYiwwQkFBSSxhQUFhO0FBQ2pCLDBCQUFJO0FBQ0YsaUNBQVMsT0FBTyxjQUFlLFNBQVM7QUFBQSxzQkFDMUMsU0FBUyxHQUFHO0FBQUEsc0JBQ1o7QUFDQSwwQkFBSTtBQUNGLHFDQUFhLE9BQU8sY0FBZSxTQUFTO0FBQUEsc0JBQzlDLFNBQVMsR0FBRztBQUFBLHNCQUNaO0FBQ0EsNkJBQU87QUFBQSx3QkFBcUI7QUFBQSx3QkFDeEI7QUFBQSx3QkFDQSxDQUFDLFVBQVUsQ0FBQyxHQUFHLGdCQUFnQjtBQUFBLDBCQUM3QixVQUFVO0FBQUEsMEJBQ1YsY0FBYztBQUFBLDBCQUNkLGVBQWU7QUFBQSwwQkFDZixpQkFBaUI7QUFBQSwwQkFDakIsUUFBUSxnQkFBZ0IsYUFBYSxLQUFLLFdBQVcsQ0FBQyxDQUFDO0FBQUEsd0JBQ3pELENBQUMsQ0FBQztBQUFBLHNCQUFDO0FBQUEsb0JBQ1Q7QUFBQSxrQkFDRjtBQUFBLGdCQUNGO0FBQUEsY0FDRixTQUFTLEdBQUc7QUFDVix3QkFBUSxJQUFJLENBQUM7QUFBQSxjQUNmO0FBRUEseUJBQVcsY0FBYyxDQUFDLEdBQUcsb0JBQW9CLEdBQUcsZ0JBQWdCLEdBQUc7QUFDckUsb0JBQUksY0FBYztBQUNsQixvQkFBSSxTQUFTLFdBQVc7QUFDeEIsb0JBQUksV0FBVyxzQkFBc0IsUUFBUSxDQUFDLFdBQVcsbUJBQW1CLFNBQVMsR0FBRyxHQUFHO0FBQ3pGLHNCQUFJLFdBQVcsbUJBQW1CLFdBQVcsR0FBRztBQUc5Qyw2QkFBUztBQUFBLGtCQUNYO0FBQ0Esc0JBQUksZ0JBQWdCO0FBQ3BCLDZCQUFXLHFCQUFxQixXQUFXLG9CQUFvQjtBQUM3RCx3QkFBSSxjQUFjLFNBQVMsR0FBRztBQUM1Qix1Q0FBaUI7QUFBQSxvQkFDbkI7QUFDQSxxQ0FBaUIsZUFBZSxrQkFBa0IsUUFBUSxLQUFNLEtBQUssQ0FBQztBQUFBLGtCQUN4RTtBQUNBLHNCQUFJLGNBQWMsU0FBUyxHQUFHO0FBQzVCLHFDQUFpQjtBQUNqQixtQ0FBZSxHQUFHLGFBQWE7QUFBQSxrQkFDakM7QUFBQSxnQkFDRjtBQUNBLHdCQUFRLG1CQUFtQixZQUFZLFNBQVMsSUFBSSxHQUFHLFdBQVcsT0FBTyxNQUFNLE9BQU8sTUFBTTtBQUFBLGNBQzlGO0FBRUEsa0JBQUksTUFBTSxPQUFPO0FBQ2pCLGtCQUFJO0FBQ0Ysc0JBQU0sT0FBTyxjQUFjLFNBQVM7QUFBQSxjQUN0QyxTQUFTLEdBQUc7QUFDVix3QkFBUSxJQUFJLENBQUM7QUFBQSxjQUNmO0FBQ0EsbUNBQXFCLGVBQWUsUUFBUSxDQUFDLEdBQUcsQ0FBQztBQUVqRCxrQkFBSTtBQUNGLHNCQUFNLFVBQVU7QUFBQSxrQkFDZCxPQUFPLE9BQU8sY0FBYyxRQUFRO0FBQUEsa0JBQ3BDLFNBQVMsT0FBTyxjQUFjLFFBQVE7QUFBQSxrQkFDdEMsU0FBUyxPQUFPLGNBQWMsUUFBUTtBQUFBLGtCQUN0QyxRQUFRLE9BQU8sY0FBYyxRQUFRO0FBQUEsa0JBQ3JDLFFBQVEsT0FBTyxjQUFjLFFBQVE7QUFBQSxnQkFDdkM7QUFDQSwyQkFBVyxLQUFLLFNBQVM7QUFDdkIsbUJBQUMsU0FBVSxRQUFRO0FBRWpCLDJCQUFPLGNBQWMsUUFBUSxNQUFNLElBQUksV0FBWTtBQUNqRCwwQkFBSSxVQUFVO0FBQ2QsK0JBQVMsS0FBSyxXQUFXO0FBQ3ZCLDRCQUFJLFdBQVcsSUFBSTtBQUNqQixxQ0FBVyxVQUFVLENBQUM7QUFBQSx3QkFDeEIsT0FBTztBQUNMLHFDQUFXLE1BQU0sVUFBVSxDQUFDO0FBQUEsd0JBQzlCO0FBQUEsc0JBQ0Y7QUFFQSw4QkFBUSxNQUFNLEVBQUUsS0FBSyxPQUFPLGNBQWMsU0FBUyxHQUFHLFNBQVM7QUFDL0QsMkNBQXFCLG9CQUFvQixRQUFRLENBQUMsUUFBUSxPQUFPLENBQUM7QUFBQSxvQkFDcEU7QUFBQSxrQkFDRixHQUFHLENBQUM7QUFBQSxnQkFDTjtBQUFBLGNBQ0YsU0FBUyxHQUFHO0FBQ1Ysd0JBQVEsSUFBSSxDQUFDO0FBQUEsY0FDZjtBQUVBLGtCQUFJO0FBQ0Ysc0JBQU0sb0JBQW9CLE9BQU8sY0FBYyxRQUFRO0FBQ3ZELHVCQUFPLGNBQWMsUUFBUSxZQUFZLFNBQVUsT0FBTyxRQUFRQSxNQUFLO0FBQ3JFLG9DQUFrQixLQUFLLE9BQU8sY0FBZSxTQUFTLE9BQU8sUUFBUUEsSUFBRztBQUN4RSxzQkFBSSxZQUFZLE9BQU87QUFDdkIsc0JBQUk7QUFDRixnQ0FBWSxPQUFPLGNBQWUsU0FBUztBQUFBLGtCQUM3QyxTQUFTLEdBQUc7QUFDViw0QkFBUSxJQUFJLENBQUM7QUFBQSxrQkFDZjtBQUNBLHVDQUFxQiwwQkFBMEIsUUFBUSxDQUFDLFNBQVMsQ0FBQztBQUFBLGdCQUNwRTtBQUVBLHNCQUFNLHVCQUF1QixPQUFPLGNBQWMsUUFBUTtBQUMxRCx1QkFBTyxjQUFjLFFBQVEsZUFBZSxTQUFVLE9BQU8sUUFBUUEsTUFBSztBQUN4RSx1Q0FBcUIsS0FBSyxPQUFPLGNBQWUsU0FBUyxPQUFPLFFBQVFBLElBQUc7QUFDM0Usc0JBQUksWUFBWSxPQUFPO0FBQ3ZCLHNCQUFJO0FBQ0YsZ0NBQVksT0FBTyxjQUFlLFNBQVM7QUFBQSxrQkFDN0MsU0FBUyxHQUFHO0FBQ1YsNEJBQVEsSUFBSSxDQUFDO0FBQUEsa0JBQ2Y7QUFDQSx1Q0FBcUIsMEJBQTBCLFFBQVEsQ0FBQyxTQUFTLENBQUM7QUFBQSxnQkFDcEU7QUFFQSxzQkFBTSxnQkFBZ0IsT0FBTyxjQUFjO0FBQzNDLHVCQUFPLGNBQWMsUUFBUSxXQUFZO0FBQ3ZDLGdDQUFjLEtBQUssT0FBTyxhQUFhO0FBQ3ZDLHVDQUFxQixpQkFBaUIsTUFBTTtBQUFBLGdCQUM5QztBQUVBLHNCQUFNLGVBQWUsT0FBTyxjQUFjO0FBQzFDLHVCQUFPLGNBQWMsT0FBTyxTQUFVQSxNQUFLLFFBQVEsZ0JBQWdCO0FBQ2pFLHdCQUFNLFlBQVksYUFBYSxLQUFLLE9BQU8sZUFBZSxHQUFHLFNBQVM7QUFDdEUsdUNBQXVDLGtCQUFrQixRQUFRLENBQUNBLE1BQUssUUFBUSxjQUFjLENBQUMsRUFBRSxLQUFLLFNBQVUsaUJBQWlCO0FBQzlILHdCQUFJLGlCQUFpQjtBQUNuQixpQ0FBVyxNQUFNO0FBQUEsb0JBQ25CO0FBQUEsa0JBQ0YsQ0FBQztBQUNELHlCQUFPO0FBQUEsZ0JBQ1Q7QUFFQSxzQkFBTSxnQkFBZ0IsT0FBTyxjQUFjO0FBQzNDLHVCQUFPLGNBQWMsUUFBUSxXQUFZO0FBQ3ZDLHNCQUFJLFlBQVksT0FBTztBQUN2QixzQkFBSTtBQUNGLGdDQUFZLE9BQU8sY0FBZSxTQUFTO0FBQUEsa0JBQzdDLFNBQVMsR0FBRztBQUNWLDRCQUFRLElBQUksQ0FBQztBQUFBLGtCQUNmO0FBQ0EsdUNBQXFCLGtCQUFrQixRQUFRLENBQUMsU0FBUyxDQUFDO0FBQzFELGdDQUFjLEtBQUssT0FBTyxhQUFhO0FBQUEsZ0JBQ3pDO0FBRUEsd0JBQVEsY0FBYztBQUFBLGtCQUNwQixlQUFlLE9BQU8sY0FBYztBQUFBLGdCQUN0QztBQUVBLHNCQUFNLGVBQWUsT0FBTyxpQkFBaUI7QUFDN0Msc0JBQU0sVUFBVSxPQUFPLGlCQUFpQixjQUFjLE9BQU87QUFDN0Qsd0JBQVEsZ0JBQWdCO0FBQ3hCLHFDQUFxQixrQkFBa0IsUUFBUSxDQUFDLFlBQVksQ0FBQztBQUM3RCxvQkFBSSxXQUFXLE1BQU07QUFDbkIsc0JBQUksaUJBQWlCLFNBQVUsV0FBVztBQUN4QywwQkFBTSxRQUFTLFVBQVUsQ0FBQyxFQUFFLE9BQXVCO0FBQ25ELHdCQUFJLFNBQVMsUUFBUSxlQUFlO0FBQ2xDLDhCQUFRLGdCQUFnQjtBQUN4QiwyQ0FBcUIsa0JBQWtCLFFBQVEsQ0FBQyxLQUFLLENBQUM7QUFBQSxvQkFDeEQ7QUFBQSxrQkFDRixDQUFDLEVBQUU7QUFBQSxvQkFDQztBQUFBLG9CQUNBLEVBQUMsU0FBUyxNQUFNLGVBQWUsTUFBTSxXQUFXLEtBQUk7QUFBQSxrQkFDeEQ7QUFBQSxnQkFDRjtBQUVBLG9CQUFJLGdCQUFnQixPQUFPLGNBQWM7QUFDekMsdUJBQU8sY0FBYyxpQkFBaUIsVUFBVSxTQUFVLEdBQUc7QUFDM0Qsd0JBQU0sZ0JBQWdCLE9BQU8sY0FBZTtBQUM1QyxzQkFBSSxrQkFBa0IsZUFBZTtBQUNuQyx5Q0FBcUIsc0JBQXNCLFFBQVEsQ0FBQyxlQUFlLGFBQWEsQ0FBQztBQUNqRixvQ0FBZ0I7QUFBQSxrQkFDbEI7QUFBQSxnQkFDRixDQUFDO0FBRUQsdUJBQU8sY0FBYyxpQkFBaUIsWUFBWSxTQUFVQyxRQUFjO0FBQ3hFLHNCQUFJLFlBQVksT0FBTztBQUN2QixzQkFBSTtBQUNGLGdDQUFZLE9BQU8sY0FBZSxTQUFTO0FBQUEsa0JBQzdDLFNBQVMsR0FBRztBQUNWLDRCQUFRLElBQUksQ0FBQztBQUFBLGtCQUNmO0FBQ0EsdUNBQXFCLDBCQUEwQixRQUFRLENBQUMsU0FBUyxDQUFDO0FBQUEsZ0JBQ3BFLENBQUM7QUFFRCx1QkFBTyxjQUFjLGlCQUFpQixVQUFVLFNBQVVBLFFBQWM7QUFDdEUsc0JBQUksSUFBSTtBQUNSLHNCQUFJLElBQUk7QUFDUixzQkFBSTtBQUNGLHdCQUFJLE9BQU8sY0FBZTtBQUMxQix3QkFBSSxPQUFPLGNBQWU7QUFBQSxrQkFDNUIsU0FBUyxHQUFHO0FBQ1YsNEJBQVEsSUFBSSxDQUFDO0FBQUEsa0JBQ2Y7QUFDQSx1Q0FBcUIsbUJBQW1CLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUFBLGdCQUN4RCxDQUFDO0FBRUQsdUJBQU8sY0FBYyxpQkFBaUIsU0FBUyxTQUFVQSxRQUFjO0FBQ3JFLHVDQUFxQixpQkFBaUIsTUFBTTtBQUFBLGdCQUM5QyxDQUFDO0FBRUQsdUJBQU8sY0FBYyxpQkFBaUIsUUFBUSxTQUFVQSxRQUFjO0FBQ3BFLHVDQUFxQixnQkFBZ0IsTUFBTTtBQUFBLGdCQUM3QyxDQUFDO0FBQUEsY0FDSCxTQUFTLEdBQUc7QUFDVix3QkFBUSxJQUFJLENBQUM7QUFBQSxjQUNmO0FBRUEsa0JBQUk7QUFDRixvQkFBSSxDQUFDLFFBQVEsU0FBUyx1Q0FBdUM7QUFDM0QseUJBQU8sY0FBYyxPQUFPLFdBQVk7QUFDdEMsMEJBQU0sSUFBSSxNQUFNLDhDQUE4QztBQUFBLGtCQUNoRTtBQUFBLGdCQUNGO0FBRUEsb0JBQUksQ0FBQyxRQUFRLFNBQVMsNEJBQTRCLENBQUMsUUFBUSxTQUFTLDRCQUE0QjtBQUM5Rix3QkFBTSxRQUFRLE9BQU8saUJBQWlCLGNBQWMsT0FBTztBQUMzRCxzQkFBSSxTQUFTLE1BQU07QUFDakIsMEJBQU0sS0FBSztBQUNYLDBCQUFNLFlBQVk7QUFDbEIsMkJBQU8saUJBQWlCLEtBQUssT0FBTyxLQUFLO0FBQUEsa0JBQzNDO0FBQUEsZ0JBQ0Y7QUFFQSxvQkFBSSxRQUFRLFNBQVMsdUJBQXVCO0FBQzFDLHdCQUFNLFFBQVEsT0FBTyxpQkFBaUIsY0FBYyxPQUFPO0FBQzNELHNCQUFJLFNBQVMsTUFBTTtBQUNqQiwwQkFBTSxLQUFLO0FBQ1gsMEJBQU0sWUFBWTtBQUNsQiwyQkFBTyxpQkFBaUIsS0FBSyxPQUFPLEtBQUs7QUFBQSxrQkFDM0M7QUFBQSxnQkFDRjtBQUVBLG9CQUFJLFFBQVEsU0FBUyx5QkFBeUI7QUFDNUMsd0JBQU0sUUFBUSxPQUFPLGlCQUFpQixjQUFjLE9BQU87QUFDM0Qsc0JBQUksU0FBUyxNQUFNO0FBQ2pCLDBCQUFNLEtBQUs7QUFDWCwwQkFBTSxZQUFZO0FBQ2xCLDJCQUFPLGlCQUFpQixLQUFLLE9BQU8sS0FBSztBQUFBLGtCQUMzQztBQUFBLGdCQUNGO0FBRUEsb0JBQUksUUFBUSxTQUFTLG9CQUFvQjtBQUN2Qyx5QkFBTyxjQUFjLGlCQUFpQixlQUFlLFFBQVEseUJBQXlCO0FBQUEsZ0JBQ3hGO0FBQUEsY0FDRixTQUFTLEdBQUc7QUFDVix3QkFBUSxJQUFJLENBQUM7QUFBQSxjQUNmO0FBRUEsbUNBQXFCLGNBQWMsUUFBUSxDQUFDLEdBQUcsQ0FBQztBQUVoRCxrQkFBSTtBQUNGLHVCQUFPLGNBQWMsY0FBYyxJQUFJLE1BQU0sa0NBQWtDLENBQUM7QUFBQSxjQUNsRixTQUFTLEdBQUc7QUFDVix3QkFBUSxJQUFJLENBQUM7QUFBQSxjQUNmO0FBQUEsWUFFRixDQUFDO0FBQUEsVUFDSDtBQUFBLFFBQ0Y7QUFBQSxRQUNBLGFBQWEsU0FBVSxhQUFtQztBQUN4RCxnQkFBTUMsVUFBUyxRQUFRO0FBQ3ZCLGNBQUlBLFdBQVUsTUFBTTtBQUNsQjtBQUFBLFVBQ0Y7QUFDQSxjQUFJO0FBQ0YsZ0JBQUksUUFBUSxTQUFTLHlDQUF5QyxZQUFZLHVDQUF1QztBQUMvRyxrQkFBSSxDQUFDLFlBQVksdUNBQXVDO0FBQ3RELGdCQUFBQSxRQUFPLGNBQWUsT0FBTyxXQUFZO0FBQ3ZDLHdCQUFNLElBQUksTUFBTSw4Q0FBOEM7QUFBQSxnQkFDaEU7QUFBQSxjQUNGLE9BQU87QUFDTCxnQkFBQUEsUUFBTyxjQUFlLE9BQU8sUUFBUSxZQUFZLGFBQWE7QUFBQSxjQUNoRTtBQUFBLFlBQ0Y7QUFFQSxnQkFBSSxRQUFRLFNBQVMsNEJBQTRCLFlBQVksNEJBQ3pELFFBQVEsU0FBUyw4QkFBOEIsWUFBWSw0QkFBNEI7QUFDekYsa0JBQUksQ0FBQyxZQUFZLDRCQUE0QixDQUFDLFlBQVksNEJBQTRCO0FBQ3BGLHNCQUFNLFFBQVFBLFFBQU8saUJBQWlCLGNBQWMsT0FBTztBQUMzRCxvQkFBSSxTQUFTLE1BQU07QUFDakIsd0JBQU0sS0FBSztBQUNYLHdCQUFNLFlBQVk7QUFDbEIsa0JBQUFBLFFBQU8saUJBQWlCLEtBQUssT0FBTyxLQUFLO0FBQUEsZ0JBQzNDO0FBQUEsY0FDRixPQUFPO0FBQ0wsc0JBQU0sZUFBZUEsUUFBTyxpQkFBaUIsZUFBZSx1RUFBdUU7QUFDbkksb0JBQUksY0FBYztBQUNoQiwrQkFBYSxPQUFPO0FBQUEsZ0JBQ3RCO0FBQUEsY0FDRjtBQUFBLFlBQ0Y7QUFFQSxnQkFBSSxRQUFRLFNBQVMseUJBQXlCLFlBQVksdUJBQXVCO0FBQy9FLGtCQUFJLFlBQVksdUJBQXVCO0FBQ3JDLHNCQUFNLFFBQVFBLFFBQU8saUJBQWlCLGNBQWMsT0FBTztBQUMzRCxvQkFBSSxTQUFTLE1BQU07QUFDakIsd0JBQU0sS0FBSztBQUNYLHdCQUFNLFlBQVk7QUFDbEIsa0JBQUFBLFFBQU8saUJBQWlCLEtBQUssT0FBTyxLQUFLO0FBQUEsZ0JBQzNDO0FBQUEsY0FDRixPQUFPO0FBQ0wsc0JBQU0sZUFBZUEsUUFBTyxpQkFBaUIsZUFBZSxnQ0FBZ0M7QUFDNUYsb0JBQUksY0FBYztBQUNoQiwrQkFBYSxPQUFPO0FBQUEsZ0JBQ3RCO0FBQUEsY0FDRjtBQUFBLFlBQ0Y7QUFFQSxnQkFBSSxRQUFRLFNBQVMsMkJBQTJCLFlBQVkseUJBQXlCO0FBQ25GLGtCQUFJLFlBQVkseUJBQXlCO0FBQ3ZDLHNCQUFNLFFBQVFBLFFBQU8saUJBQWlCLGNBQWMsT0FBTztBQUMzRCxvQkFBSSxTQUFTLE1BQU07QUFDakIsd0JBQU0sS0FBSztBQUNYLHdCQUFNLFlBQVk7QUFDbEIsa0JBQUFBLFFBQU8saUJBQWlCLEtBQUssT0FBTyxLQUFLO0FBQUEsZ0JBQzNDO0FBQUEsY0FDRixPQUFPO0FBQ0wsc0JBQU0sZUFBZUEsUUFBTyxpQkFBaUIsZUFBZSxrQ0FBa0M7QUFDOUYsb0JBQUksY0FBYztBQUNoQiwrQkFBYSxPQUFPO0FBQUEsZ0JBQ3RCO0FBQUEsY0FDRjtBQUFBLFlBQ0Y7QUFFQSxnQkFBSSxRQUFRLFNBQVMsc0JBQXNCLFlBQVksb0JBQW9CO0FBQ3pFLGtCQUFJLFlBQVksb0JBQW9CO0FBQ2xDLGdCQUFBQSxRQUFPLGVBQWUsaUJBQWlCLGVBQWUsUUFBUSx5QkFBeUI7QUFBQSxjQUN6RixPQUFPO0FBQ0wsZ0JBQUFBLFFBQU8sZUFBZSxvQkFBb0IsZUFBZSxRQUFRLHlCQUF5QjtBQUFBLGNBQzVGO0FBQUEsWUFDRjtBQUFBLFVBQ0YsU0FBUyxHQUFHO0FBQ1Ysb0JBQVEsSUFBSSxDQUFDO0FBQUEsVUFDZjtBQUVBLGtCQUFRLFdBQVc7QUFBQSxRQUNyQjtBQUFBLFFBQ0EsUUFBUSxXQUFZO0FBQ2xCLGNBQUlBLFVBQVMsUUFBUTtBQUNyQixjQUFJQSxXQUFVLFFBQVFBLFFBQU8saUJBQWlCLE1BQU07QUFDbEQsZ0JBQUk7QUFDRixjQUFBQSxRQUFPLGNBQWMsU0FBUyxPQUFPO0FBQUEsWUFDdkMsU0FBUyxHQUFHO0FBQ1Ysc0JBQVEsSUFBSSxDQUFDO0FBQ2IsY0FBQUEsUUFBTyxjQUFjLFNBQVMsT0FBT0EsUUFBTztBQUFBLFlBQzlDO0FBQUEsVUFDRjtBQUFBLFFBQ0Y7QUFBQSxRQUNBLFFBQVEsV0FBWTtBQUNsQixjQUFJQSxVQUFTLFFBQVE7QUFDckIsY0FBSUEsV0FBVSxNQUFNO0FBQ2xCLGdCQUFJO0FBQ0YsY0FBQUEsUUFBTyxlQUFlLFFBQVEsS0FBSztBQUFBLFlBQ3JDLFNBQVMsR0FBRztBQUNWLHNCQUFRLElBQUksQ0FBQztBQUFBLFlBQ2Y7QUFBQSxVQUNGO0FBQUEsUUFDRjtBQUFBLFFBQ0EsV0FBVyxXQUFZO0FBQ3JCLGNBQUlBLFVBQVMsUUFBUTtBQUNyQixjQUFJQSxXQUFVLE1BQU07QUFDbEIsZ0JBQUk7QUFDRixjQUFBQSxRQUFPLGVBQWUsUUFBUSxRQUFRO0FBQUEsWUFDeEMsU0FBUyxHQUFHO0FBQ1Ysc0JBQVEsSUFBSSxDQUFDO0FBQUEsWUFDZjtBQUFBLFVBQ0Y7QUFBQSxRQUNGO0FBQUEsUUFDQSxpQkFBaUIsU0FBVSxPQUFPO0FBQ2hDLGNBQUlBLFVBQVMsUUFBUTtBQUNyQixjQUFJQSxXQUFVLE1BQU07QUFDbEIsZ0JBQUk7QUFDRixjQUFBQSxRQUFPLGVBQWUsUUFBUSxHQUFHLEtBQUs7QUFBQSxZQUN4QyxTQUFTLEdBQUc7QUFDVixzQkFBUSxJQUFJLENBQUM7QUFBQSxZQUNmO0FBQUEsVUFDRjtBQUFBLFFBQ0Y7QUFBQSxRQUNBLG9CQUFvQixTQUFVLFFBQVE7QUFDcEMsZ0JBQU1BLFVBQVMsUUFBUTtBQUN2QixjQUFJLFNBQVM7QUFDYixjQUFJQSxXQUFVLE1BQU07QUFDbEIsZ0JBQUk7QUFDRix1QkFBUyxLQUFLLFVBQVVBLFFBQU8sZUFBZSxLQUFLLE1BQU0sQ0FBQztBQUFBLFlBQzVELFNBQVMsR0FBRztBQUFBLFlBQ1o7QUFBQSxVQUNGO0FBQ0EsaUJBQU87QUFBQSxRQUNUO0FBQUEsUUFDQSxhQUFhLFdBQVk7QUFDdkIsZ0JBQU1BLFVBQVMsUUFBUTtBQUN2QixjQUFJQSxXQUFVLE1BQU07QUFDbEIsZ0JBQUk7QUFDRixjQUFBQSxRQUFPLGVBQWUsS0FBSztBQUFBLFlBQzdCLFNBQVMsR0FBRztBQUNWLHNCQUFRLElBQUksQ0FBQztBQUFBLFlBQ2Y7QUFBQSxVQUNGO0FBQUEsUUFDRjtBQUFBLFFBQ0EsUUFBUSxXQUFZO0FBQ2xCLGdCQUFNQSxVQUFTLFFBQVE7QUFDdkIsY0FBSSxNQUFNQSxTQUFRO0FBQ2xCLGNBQUk7QUFDRixrQkFBTUEsU0FBUSxlQUFlLFNBQVM7QUFBQSxVQUN4QyxTQUFTLEdBQUc7QUFDVixvQkFBUSxJQUFJLENBQUM7QUFBQSxVQUNmO0FBQ0EsaUJBQU87QUFBQSxRQUNUO0FBQUEsUUFDQSxVQUFVLFdBQVk7QUFDcEIsZ0JBQU1BLFVBQVMsUUFBUTtBQUN2QixjQUFJLFFBQVE7QUFDWixjQUFJO0FBQ0Ysb0JBQVFBLFNBQVEsaUJBQWlCO0FBQUEsVUFDbkMsU0FBUyxHQUFHO0FBQ1Ysb0JBQVEsSUFBSSxDQUFDO0FBQUEsVUFDZjtBQUNBLGlCQUFPO0FBQUEsUUFDVDtBQUFBLFFBQ0EsNkJBQTZCLFNBQVUsU0FBUyx5QkFBeUI7QUFDdkUsZ0JBQU1BLFVBQVMsUUFBUTtBQUN2QixjQUFJO0FBQ0Ysa0JBQU0sSUFBSUEsU0FBUTtBQUNsQixnQkFBSSxLQUFLLE1BQU07QUFDYjtBQUFBLFlBQ0Y7QUFDQSxrQkFBTSxTQUFTLEVBQUUsY0FBYyxRQUFRO0FBQ3ZDLHVCQUFXLE9BQU8sT0FBTyxLQUFLLHVCQUF1QixHQUFHO0FBQ3RELGtCQUFJLHdCQUF3QixHQUFHLEtBQUssTUFBTTtBQUV4Qyx1QkFBTyxHQUFHLElBQUksd0JBQXdCLEdBQUc7QUFBQSxjQUMzQztBQUFBLFlBQ0Y7QUFDQSxnQkFBSSxPQUFPLE1BQU0sTUFBTTtBQUNyQixxQkFBTyxTQUFTLFdBQVk7QUFDMUIscUNBQXFCLDBCQUEwQixRQUFRLFFBQVEsQ0FBQyxPQUFPLEVBQUUsQ0FBQztBQUFBLGNBQzVFO0FBQ0EscUJBQU8sVUFBVSxXQUFZO0FBQzNCLHFDQUFxQix5QkFBeUIsUUFBUSxRQUFRLENBQUMsT0FBTyxFQUFFLENBQUM7QUFBQSxjQUMzRTtBQUFBLFlBQ0Y7QUFDQSxtQkFBTyxNQUFNO0FBQ2IsZ0JBQUksRUFBRSxRQUFRLE1BQU07QUFDbEIsZ0JBQUUsS0FBSyxZQUFZLE1BQU07QUFBQSxZQUMzQjtBQUFBLFVBQ0YsU0FBUyxHQUFHO0FBQ1Ysb0JBQVEsSUFBSSxDQUFDO0FBQUEsVUFDZjtBQUFBLFFBQ0Y7QUFBQSxRQUNBLGVBQWUsU0FBVSxRQUFRO0FBQy9CLGdCQUFNQSxVQUFTLFFBQVE7QUFDdkIsY0FBSTtBQUNGLGtCQUFNLElBQUlBLFNBQVE7QUFDbEIsZ0JBQUksS0FBSyxNQUFNO0FBQ2I7QUFBQSxZQUNGO0FBQ0Esa0JBQU0sUUFBUSxFQUFFLGNBQWMsT0FBTztBQUNyQyxrQkFBTSxZQUFZO0FBQ2xCLGdCQUFJLEVBQUUsUUFBUSxNQUFNO0FBQ2xCLGdCQUFFLEtBQUssWUFBWSxLQUFLO0FBQUEsWUFDMUI7QUFBQSxVQUNGLFNBQVMsR0FBRztBQUNWLG9CQUFRLElBQUksQ0FBQztBQUFBLFVBQ2Y7QUFBQSxRQUNGO0FBQUEsUUFDQSxzQkFBc0IsU0FBVSxTQUFTLDBCQUEwQjtBQUNqRSxnQkFBTUEsVUFBUyxRQUFRO0FBQ3ZCLGNBQUk7QUFDRixrQkFBTSxJQUFJQSxTQUFRO0FBQ2xCLGdCQUFJLEtBQUssTUFBTTtBQUNiO0FBQUEsWUFDRjtBQUNBLGtCQUFNLE9BQU8sRUFBRSxjQUFjLE1BQU07QUFDbkMsdUJBQVcsT0FBTyxPQUFPLEtBQUssd0JBQXdCLEdBQUc7QUFDdkQsa0JBQUkseUJBQXlCLEdBQUcsS0FBSyxNQUFNO0FBRXpDLHFCQUFLLEdBQUcsSUFBSSx5QkFBeUIsR0FBRztBQUFBLGNBQzFDO0FBQUEsWUFDRjtBQUNBLGlCQUFLLE9BQU87QUFDWixnQkFBSSxzQkFBc0I7QUFDMUIsZ0JBQUkseUJBQXlCLHFCQUFxQjtBQUNoRCxvQ0FBc0I7QUFBQSxZQUN4QjtBQUNBLGlCQUFLLE1BQU0sc0JBQXNCO0FBQ2pDLGlCQUFLLE9BQU87QUFDWixnQkFBSSxFQUFFLFFBQVEsTUFBTTtBQUNsQixnQkFBRSxLQUFLLFlBQVksSUFBSTtBQUFBLFlBQ3pCO0FBQUEsVUFDRixTQUFTLEdBQUc7QUFDVixvQkFBUSxJQUFJLENBQUM7QUFBQSxVQUNmO0FBQUEsUUFDRjtBQUFBLFFBQ0EsVUFBVSxTQUFVLEdBQUcsR0FBRyxVQUFVO0FBQ2xDLGdCQUFNQSxVQUFTLFFBQVE7QUFDdkIsY0FBSTtBQUNGLGdCQUFJLFVBQVU7QUFDWixjQUFBQSxTQUFRLGVBQWUsU0FBUyxFQUFDLEtBQUssR0FBRyxNQUFNLEdBQUcsVUFBVSxTQUFRLENBQUM7QUFBQSxZQUN2RSxPQUFPO0FBQ0wsY0FBQUEsU0FBUSxlQUFlLFNBQVMsR0FBRyxDQUFDO0FBQUEsWUFDdEM7QUFBQSxVQUNGLFNBQVMsR0FBRztBQUNWLG9CQUFRLElBQUksQ0FBQztBQUFBLFVBQ2Y7QUFBQSxRQUNGO0FBQUEsUUFDQSxVQUFVLFNBQVUsR0FBRyxHQUFHLFVBQVU7QUFDbEMsZ0JBQU1BLFVBQVMsUUFBUTtBQUN2QixjQUFJO0FBQ0YsZ0JBQUksVUFBVTtBQUNaLGNBQUFBLFNBQVEsZUFBZSxTQUFTLEVBQUMsS0FBSyxHQUFHLE1BQU0sR0FBRyxVQUFVLFNBQVEsQ0FBQztBQUFBLFlBQ3ZFLE9BQU87QUFDTCxjQUFBQSxTQUFRLGVBQWUsU0FBUyxHQUFHLENBQUM7QUFBQSxZQUN0QztBQUFBLFVBQ0YsU0FBUyxHQUFHO0FBQ1Ysb0JBQVEsSUFBSSxDQUFDO0FBQUEsVUFDZjtBQUFBLFFBQ0Y7QUFBQSxRQUNBLGtCQUFrQixXQUFZO0FBQzVCLGdCQUFNQSxVQUFTLFFBQVE7QUFDdkIsY0FBSTtBQUNGLFlBQUFBLFNBQVEsZUFBZSxNQUFNO0FBQUEsVUFDL0IsU0FBUyxHQUFHO0FBQ1Ysb0JBQVEsSUFBSSxDQUFDO0FBQUEsVUFDZjtBQUFBLFFBQ0Y7QUFBQSxRQUNBLGtCQUFrQixXQUFZO0FBQzVCLGdCQUFNQSxVQUFTLFFBQVE7QUFDdkIsY0FBSTtBQUNGLG1CQUFPQSxTQUFRLGlCQUFpQixnQkFBZ0I7QUFBQSxVQUNsRCxTQUFTLEdBQUc7QUFDVixvQkFBUSxJQUFJLENBQUM7QUFBQSxVQUNmO0FBQ0EsaUJBQU87QUFBQSxRQUNUO0FBQUEsUUFDQSxpQkFBaUIsV0FBWTtBQUMzQixnQkFBTUEsVUFBUyxRQUFRO0FBQ3ZCLGNBQUk7QUFDRixtQkFBT0EsU0FBUSxpQkFBaUIsZ0JBQWdCO0FBQUEsVUFDbEQsU0FBUyxHQUFHO0FBQ1Ysb0JBQVEsSUFBSSxDQUFDO0FBQUEsVUFDZjtBQUNBLGlCQUFPO0FBQUEsUUFDVDtBQUFBLFFBQ0EsaUJBQWlCLFdBQVk7QUFDM0IsZ0JBQU1BLFVBQVMsUUFBUTtBQUN2QixjQUFJO0FBQ0YsZ0JBQUk7QUFDSixrQkFBTSxJQUFJQSxTQUFRO0FBQ2xCLGdCQUFJLEtBQUssTUFBTTtBQUNiLHFCQUFPO0FBQUEsWUFDVDtBQUNBLGdCQUFJLEVBQUUsY0FBYztBQUNsQixvQkFBTSxFQUFFLGFBQWEsR0FBRyxTQUFTO0FBQUEsWUFDbkMsV0FBVyxFQUFFLFNBQVMsY0FBYztBQUNsQyxvQkFBTSxFQUFFLFNBQVMsYUFBYSxHQUFHLFNBQVM7QUFBQSxZQUU1QyxXQUFXLEVBQUUsU0FBUyxXQUFXO0FBRS9CLG9CQUFNLEVBQUUsU0FBUyxVQUFVLFlBQVksRUFBRTtBQUFBLFlBQzNDO0FBQ0EsbUJBQU87QUFBQSxVQUNULFNBQVMsR0FBRztBQUNWLG9CQUFRLElBQUksQ0FBQztBQUFBLFVBQ2Y7QUFDQSxpQkFBTztBQUFBLFFBQ1Q7QUFBQSxRQUNBLFlBQVksV0FBWTtBQUN0QixnQkFBTUEsVUFBUyxRQUFRO0FBQ3ZCLGNBQUk7QUFDRixtQkFBT0EsU0FBUSxlQUFlO0FBQUEsVUFDaEMsU0FBUyxHQUFHO0FBQ1Ysb0JBQVEsSUFBSSxDQUFDO0FBQUEsVUFDZjtBQUNBLGlCQUFPO0FBQUEsUUFDVDtBQUFBLFFBQ0EsWUFBWSxXQUFZO0FBQ3RCLGdCQUFNQSxVQUFTLFFBQVE7QUFDdkIsY0FBSTtBQUNGLG1CQUFPQSxTQUFRLGVBQWU7QUFBQSxVQUNoQyxTQUFTLEdBQUc7QUFDVixvQkFBUSxJQUFJLENBQUM7QUFBQSxVQUNmO0FBQ0EsaUJBQU87QUFBQSxRQUNUO0FBQUEsUUFDQSxpQkFBaUIsV0FBWTtBQUMzQixnQkFBTUEsVUFBUyxRQUFRO0FBQ3ZCLGNBQUk7QUFDRixtQkFBT0EsU0FBUSxlQUFlLG1CQUFtQjtBQUFBLFVBQ25ELFNBQVMsR0FBRztBQUNWLG9CQUFRLElBQUksQ0FBQztBQUFBLFVBQ2Y7QUFDQSxpQkFBTztBQUFBLFFBQ1Q7QUFBQSxRQUNBLHFCQUFxQixXQUFZO0FBQy9CLGdCQUFNQSxVQUFTLFFBQVE7QUFDdkIsY0FBSTtBQUNGLG9CQUFRQSxTQUFRLGlCQUFpQixLQUFLLGdCQUFnQixNQUFNQSxTQUFRLGVBQWUsZUFBZTtBQUFBLFVBQ3BHLFNBQVMsR0FBRztBQUNWLG9CQUFRLElBQUksQ0FBQztBQUFBLFVBQ2Y7QUFDQSxpQkFBTztBQUFBLFFBQ1Q7QUFBQSxRQUNBLHVCQUF1QixXQUFZO0FBQ2pDLGdCQUFNQSxVQUFTLFFBQVE7QUFDdkIsY0FBSTtBQUNGLG9CQUFRQSxTQUFRLGlCQUFpQixLQUFLLGVBQWUsTUFBTUEsU0FBUSxlQUFlLGNBQWM7QUFBQSxVQUNsRyxTQUFTLEdBQUc7QUFDVixvQkFBUSxJQUFJLENBQUM7QUFBQSxVQUNmO0FBQ0EsaUJBQU87QUFBQSxRQUNUO0FBQUEsUUFDQSxTQUFTLFdBQVk7QUFDbkIsZ0JBQU1DLG1CQUFrQixRQUFRO0FBQ2hDLGNBQUksUUFBUTtBQUNaLGNBQUksU0FBUztBQUNiLGNBQUlBLG9CQUFtQixNQUFNO0FBQzNCLGdCQUFJQSxpQkFBZ0IsTUFBTSxTQUFTLFFBQVFBLGlCQUFnQixNQUFNLFNBQVMsTUFBTUEsaUJBQWdCLE1BQU0sTUFBTSxRQUFRLElBQUksSUFBSSxHQUFHO0FBQzdILHNCQUFRLFdBQVdBLGlCQUFnQixNQUFNLEtBQUs7QUFBQSxZQUNoRDtBQUNBLGdCQUFJLFNBQVMsUUFBUSxTQUFTLEdBQUs7QUFDakMsc0JBQVFBLGlCQUFnQixzQkFBc0IsRUFBRTtBQUFBLFlBQ2xEO0FBQ0EsZ0JBQUlBLGlCQUFnQixNQUFNLFVBQVUsUUFBUUEsaUJBQWdCLE1BQU0sVUFBVSxNQUFNQSxpQkFBZ0IsTUFBTSxPQUFPLFFBQVEsSUFBSSxJQUFJLEdBQUc7QUFDaEksdUJBQVMsV0FBV0EsaUJBQWdCLE1BQU0sTUFBTTtBQUFBLFlBQ2xEO0FBQ0EsZ0JBQUksVUFBVSxRQUFRLFVBQVUsR0FBSztBQUNuQyx1QkFBU0EsaUJBQWdCLHNCQUFzQixFQUFFO0FBQUEsWUFDbkQ7QUFBQSxVQUNGO0FBQ0EsaUJBQU87QUFBQSxZQUNMO0FBQUEsWUFDQTtBQUFBLFVBQ0Y7QUFBQSxRQUNGO0FBQUEsTUFDRjtBQUVBLGFBQU87QUFBQSxJQUNUO0FBQUEsSUFDQSx5QkFBeUIsU0FBVSxXQUFtQjtBQUNwRCxhQUFRLElBQUksS0FBSyxTQUFTLEVBQUcsWUFBWTtBQUFBLElBQzNDO0FBQUEsSUFDQSwwQkFBMEIsU0FBVSxRQUFnQixRQUF5QixNQUFjO0FBQ3pGLFlBQU0sSUFBSSxNQUFNLHlCQUF5QjtBQUFBLElBQzNDO0FBQUEsSUFDQSx5QkFBeUIsU0FBVSxRQUFnQixRQUF5QixNQUFjO0FBQ3hGLFlBQU0sSUFBSSxNQUFNLHlCQUF5QjtBQUFBLElBQzNDO0FBQUEsSUFDQSxxQkFBcUIsU0FBVSxRQUFnQixRQUF5QixNQUFjO0FBQ3BGLFVBQUk7QUFDRixjQUFNLFNBQVMsT0FBTyw0QkFBNEIsd0JBQXdCLFFBQVEsUUFBUSxJQUFJO0FBQzlGLGVBQU8sVUFBVSxPQUFPLEtBQUssTUFBTSxNQUFNLElBQUk7QUFBQSxNQUMvQyxTQUFTLElBQUk7QUFDWCxZQUFJO0FBQ0YsZ0JBQU0sVUFBVSxPQUFPLDRCQUE0Qix5QkFBeUIsUUFBUSxRQUFRLElBQUk7QUFDaEcsaUJBQU8sUUFBUSxLQUFLLFNBQVUsUUFBUTtBQUNwQyxtQkFBTyxVQUFVLE9BQU8sS0FBSyxNQUFNLE1BQU0sSUFBSTtBQUFBLFVBQy9DLENBQUM7QUFBQSxRQUNILFNBQVMsSUFBSTtBQUNYLGlCQUFPO0FBQUEsUUFDVDtBQUFBLE1BQ0Y7QUFBQSxJQUNGO0FBQUEsRUFDRjtBQUVBLE1BQUksdUJBQXVCLE9BQU8sNEJBQTRCO0FBQ2hFLEdBQUc7IiwKICAibmFtZXMiOiBbInVybCIsICJldmVudCIsICJpZnJhbWUiLCAiaWZyYW1lQ29udGFpbmVyIl0KfQo= diff --git a/flutter_inappwebview_web/lib/src/cookie_manager.dart b/flutter_inappwebview_web/lib/src/cookie_manager.dart index a173b471e..d4ec0b2dd 100755 --- a/flutter_inappwebview_web/lib/src/cookie_manager.dart +++ b/flutter_inappwebview_web/lib/src/cookie_manager.dart @@ -47,6 +47,14 @@ class WebPlatformCookieManager extends PlatformCookieManager initMethodCallHandler(); } + static final WebPlatformCookieManager _staticValue = WebPlatformCookieManager( + WebPlatformCookieManagerCreationParams( + PlatformCookieManagerCreationParams())); + + factory WebPlatformCookieManager.static() { + return _staticValue; + } + static WebPlatformCookieManager? _instance; ///Gets the [WebPlatformCookieManager] shared instance. @@ -81,7 +89,6 @@ class WebPlatformCookieManager extends PlatformCookieManager assert(url.toString().isNotEmpty); assert(name.isNotEmpty); - assert(value.isNotEmpty); assert(path.isNotEmpty); await _setCookieWithJavaScript( diff --git a/flutter_inappwebview_web/lib/src/in_app_webview/headless_in_app_webview.dart b/flutter_inappwebview_web/lib/src/in_app_webview/headless_in_app_webview.dart index 0ac6a2c89..c25de0408 100644 --- a/flutter_inappwebview_web/lib/src/in_app_webview/headless_in_app_webview.dart +++ b/flutter_inappwebview_web/lib/src/in_app_webview/headless_in_app_webview.dart @@ -30,8 +30,10 @@ class WebPlatformHeadlessInAppWebViewCreationParams super.shouldOverrideUrlLoading, super.onLoadResource, super.onScrollChanged, - @Deprecated('Use onDownloadStartRequest instead') super.onDownloadStart, + @Deprecated('Use onDownloadStarting instead') super.onDownloadStart, + @Deprecated('Use onDownloadStarting instead') super.onDownloadStartRequest, + super.onDownloadStarting, @Deprecated('Use onLoadResourceWithCustomScheme instead') super.onLoadResourceCustomScheme, super.onLoadResourceWithCustomScheme, @@ -148,6 +150,7 @@ class WebPlatformHeadlessInAppWebViewCreationParams onScrollChanged: params.onScrollChanged, onDownloadStart: params.onDownloadStart, onDownloadStartRequest: params.onDownloadStartRequest, + onDownloadStarting: params.onDownloadStarting, onLoadResourceCustomScheme: params.onLoadResourceCustomScheme, onLoadResourceWithCustomScheme: params.onLoadResourceWithCustomScheme, @@ -265,6 +268,14 @@ class WebPlatformHeadlessInAppWebView extends PlatformHeadlessInAppWebView id = IdGenerator.generate(); } + static final WebPlatformHeadlessInAppWebView _staticValue = + WebPlatformHeadlessInAppWebView( + WebPlatformHeadlessInAppWebViewCreationParams()); + + factory WebPlatformHeadlessInAppWebView.static() { + return _staticValue; + } + @override WebPlatformInAppWebViewController? get webViewController => _webViewController; @@ -350,7 +361,8 @@ class WebPlatformHeadlessInAppWebView extends PlatformHeadlessInAppWebView if (params.onLoadResource != null && settings.useOnLoadResource == null) { settings.useOnLoadResource = true; } - if (params.onDownloadStartRequest != null && + if ((params.onDownloadStartRequest != null || + params.onDownloadStarting != null) && settings.useOnDownloadStart == null) { settings.useOnDownloadStart = true; } diff --git a/flutter_inappwebview_web/lib/src/in_app_webview/in_app_webview.dart b/flutter_inappwebview_web/lib/src/in_app_webview/in_app_webview.dart index 89777617f..2cc001260 100755 --- a/flutter_inappwebview_web/lib/src/in_app_webview/in_app_webview.dart +++ b/flutter_inappwebview_web/lib/src/in_app_webview/in_app_webview.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import '../../web/web_platform_manager.dart'; +import '../../web/in_app_webview_manager.dart'; import 'headless_in_app_webview.dart'; import 'in_app_webview_controller.dart'; @@ -33,8 +33,10 @@ class WebPlatformInAppWebViewWidgetCreationParams super.shouldOverrideUrlLoading, super.onLoadResource, super.onScrollChanged, - @Deprecated('Use onDownloadStartRequest instead') super.onDownloadStart, + @Deprecated('Use onDownloadStarting instead') super.onDownloadStart, + @Deprecated('Use onDownloadStarting instead') super.onDownloadStartRequest, + super.onDownloadStarting, @Deprecated('Use onLoadResourceWithCustomScheme instead') super.onLoadResourceCustomScheme, super.onLoadResourceWithCustomScheme, @@ -157,6 +159,7 @@ class WebPlatformInAppWebViewWidgetCreationParams onScrollChanged: params.onScrollChanged, onDownloadStart: params.onDownloadStart, onDownloadStartRequest: params.onDownloadStartRequest, + onDownloadStarting: params.onDownloadStarting, onLoadResourceCustomScheme: params.onLoadResourceCustomScheme, onLoadResourceWithCustomScheme: params.onLoadResourceWithCustomScheme, @@ -269,6 +272,14 @@ class WebPlatformInAppWebViewWidget extends PlatformInAppWebViewWidget { WebPlatformHeadlessInAppWebView? get _macosHeadlessInAppWebView => _webPlatformParams.headlessWebView as WebPlatformHeadlessInAppWebView?; + static final WebPlatformInAppWebViewWidget _staticValue = + WebPlatformInAppWebViewWidget( + WebPlatformInAppWebViewWidgetCreationParams()); + + factory WebPlatformInAppWebViewWidget.static() { + return _staticValue; + } + @override Widget build(BuildContext context) { final initialSettings = @@ -287,16 +298,19 @@ class WebPlatformInAppWebViewWidget extends PlatformInAppWebViewWidget { return HtmlElementView( viewType: 'com.pichillilorenzo/flutter_inappwebview', onPlatformViewCreated: (int viewId) { - var webViewHtmlElement = WebPlatformManager.webViews[viewId]!; + var webViewHtmlElement = InAppWebViewManager.webViews[viewId]!; webViewHtmlElement.initialSettings = initialSettings; webViewHtmlElement.initialUrlRequest = _webPlatformParams.initialUrlRequest; webViewHtmlElement.initialFile = _webPlatformParams.initialFile; webViewHtmlElement.initialData = _webPlatformParams.initialData; + webViewHtmlElement.initialUserScripts = + _webPlatformParams.initialUserScripts; webViewHtmlElement.headlessWebViewId = _webPlatformParams.headlessWebView?.isRunning() ?? false ? _webPlatformParams.headlessWebView?.id : null; + webViewHtmlElement.windowId = _webPlatformParams.windowId; webViewHtmlElement.prepare(); if (webViewHtmlElement.headlessWebViewId == null) { webViewHtmlElement.makeInitialLoad(); @@ -334,7 +348,8 @@ class WebPlatformInAppWebViewWidget extends PlatformInAppWebViewWidget { settings.useOnLoadResource == null) { settings.useOnLoadResource = true; } - if (_webPlatformParams.onDownloadStartRequest != null && + if ((_webPlatformParams.onDownloadStartRequest != null || + _webPlatformParams.onDownloadStarting != null) && settings.useOnDownloadStart == null) { settings.useOnDownloadStart = true; } diff --git a/flutter_inappwebview_web/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_web/lib/src/in_app_webview/in_app_webview_controller.dart index 7a824fad9..333b44812 100644 --- a/flutter_inappwebview_web/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/flutter_inappwebview_web/lib/src/in_app_webview/in_app_webview_controller.dart @@ -1,16 +1,15 @@ +import 'dart:collection'; import 'dart:convert'; import 'dart:core'; -import 'dart:typed_data'; -import 'dart:ui'; +import 'dart:developer' as developer; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; import '../web_storage/web_storage.dart'; - -import 'headless_in_app_webview.dart'; import '_static_channel.dart'; +import 'headless_in_app_webview.dart'; /// Object specifying creation parameters for creating a [WebPlatformInAppWebViewController]. /// @@ -43,6 +42,11 @@ class WebPlatformInAppWebViewController extends PlatformInAppWebViewController // ignore: unused_field static final MethodChannel _staticChannel = IN_APP_WEBVIEW_STATIC_CHANNEL; + Map> _userScripts = { + UserScriptInjectionTime.AT_DOCUMENT_START: [], + UserScriptInjectionTime.AT_DOCUMENT_END: [] + }; + Map _javaScriptHandlersMap = HashMap(); Map _injectedScriptsFromURL = {}; dynamic _controllerFromPlatform; @@ -143,6 +147,11 @@ class WebPlatformInAppWebViewController extends PlatformInAppWebViewController _controllerFromPlatform, createWindowAction); } break; + case "onCloseWindow": + if ((webviewParams != null && webviewParams!.onCloseWindow != null)) { + webviewParams!.onCloseWindow!(_controllerFromPlatform); + } + break; case "onTitleChanged": if ((webviewParams != null && webviewParams!.onTitleChanged != null)) { String? title = call.arguments["title"]; @@ -225,6 +234,40 @@ class WebPlatformInAppWebViewController extends PlatformInAppWebViewController onErrorCallback(); } break; + case "onCallJsHandler": + String handlerName = call.arguments["handlerName"]; + Map handlerDataMap = + call.arguments["data"].cast(); + // decode args to json + handlerDataMap["args"] = jsonDecode(handlerDataMap["args"]); + final handlerData = + JavaScriptHandlerFunctionData.fromMap(handlerDataMap)!; + + _debugLog(handlerName, handlerData); + + if (_javaScriptHandlersMap.containsKey(handlerName)) { + // convert result to json + try { + var jsHandlerResult = null; + if (_javaScriptHandlersMap[handlerName] + is JavaScriptHandlerCallback) { + jsHandlerResult = await (_javaScriptHandlersMap[handlerName] + as JavaScriptHandlerCallback)(handlerData.args); + } else if (_javaScriptHandlersMap[handlerName] + is JavaScriptHandlerFunction) { + jsHandlerResult = await (_javaScriptHandlersMap[handlerName] + as JavaScriptHandlerFunction)(handlerData); + } else { + jsHandlerResult = await _javaScriptHandlersMap[handlerName]!(); + } + return jsonEncode(jsHandlerResult); + } catch (error, stacktrace) { + developer.log(error.toString() + '\n' + stacktrace.toString(), + name: 'JavaScript Handler "$handlerName"'); + throw Exception(error.toString().replaceFirst('Exception: ', '')); + } + } + break; default: throw UnimplementedError("Unimplemented ${call.method} method"); } @@ -822,6 +865,129 @@ class WebPlatformInAppWebViewController extends PlatformInAppWebViewController false; } + @override + void addJavaScriptHandler( + {required String handlerName, required Function callback}) { + assert(!kJavaScriptHandlerForbiddenNames.contains(handlerName), + '"$handlerName" is a forbidden name!'); + this._javaScriptHandlersMap[handlerName] = (callback); + } + + @override + Function? removeJavaScriptHandler({required String handlerName}) { + return this._javaScriptHandlersMap.remove(handlerName); + } + + @override + bool hasJavaScriptHandler({required String handlerName}) { + return this._javaScriptHandlersMap.containsKey(handlerName); + } + + @override + Future addUserScript({required UserScript userScript}) async { + Map args = {}; + args.putIfAbsent('userScript', () => userScript.toMap()); + if (!(_userScripts[userScript.injectionTime]?.contains(userScript) ?? + false)) { + _userScripts[userScript.injectionTime]?.add(userScript); + await channel?.invokeMethod('addUserScript', args); + } + } + + @override + Future addUserScripts({required List userScripts}) async { + for (var i = 0; i < userScripts.length; i++) { + await addUserScript(userScript: userScripts[i]); + } + } + + @override + Future removeUserScript({required UserScript userScript}) async { + var index = _userScripts[userScript.injectionTime]?.indexOf(userScript); + if (index == null || index == -1) { + return false; + } + + _userScripts[userScript.injectionTime]?.remove(userScript); + Map args = {}; + args.putIfAbsent('userScript', () => userScript.toMap()); + args.putIfAbsent('index', () => index); + await channel?.invokeMethod('removeUserScript', args); + + return true; + } + + @override + Future removeUserScriptsByGroupName({required String groupName}) async { + final List userScriptsAtDocumentStart = List.from( + _userScripts[UserScriptInjectionTime.AT_DOCUMENT_START] ?? []); + for (final userScript in userScriptsAtDocumentStart) { + if (userScript.groupName == groupName) { + _userScripts[userScript.injectionTime]?.remove(userScript); + } + } + + final List userScriptsAtDocumentEnd = + List.from(_userScripts[UserScriptInjectionTime.AT_DOCUMENT_END] ?? []); + for (final userScript in userScriptsAtDocumentEnd) { + if (userScript.groupName == groupName) { + _userScripts[userScript.injectionTime]?.remove(userScript); + } + } + + Map args = {}; + args.putIfAbsent('groupName', () => groupName); + await channel?.invokeMethod('removeUserScriptsByGroupName', args); + } + + @override + Future removeUserScripts( + {required List userScripts}) async { + for (final userScript in userScripts) { + await removeUserScript(userScript: userScript); + } + } + + @override + Future removeAllUserScripts() async { + _userScripts[UserScriptInjectionTime.AT_DOCUMENT_START]?.clear(); + _userScripts[UserScriptInjectionTime.AT_DOCUMENT_END]?.clear(); + + Map args = {}; + await channel?.invokeMethod('removeAllUserScripts', args); + } + + @override + bool hasUserScript({required UserScript userScript}) { + return _userScripts[userScript.injectionTime]?.contains(userScript) ?? + false; + } + + @override + Future setJavaScriptBridgeName(String bridgeName) async { + assert(RegExp(r'^[a-zA-Z_]\w*$').hasMatch(bridgeName), + 'bridgeName must be a non-empty string with only alphanumeric and underscore characters. It can\'t start with a number.'); + Map args = {}; + args.putIfAbsent('bridgeName', () => bridgeName); + await _staticChannel.invokeMethod('setJavaScriptBridgeName', args); + } + + @override + Future getJavaScriptBridgeName() async { + Map args = {}; + return await _staticChannel.invokeMethod( + 'getJavaScriptBridgeName', args) ?? + ''; + } + + @override + Future getDefaultUserAgent() async { + Map args = {}; + return await _staticChannel.invokeMethod( + 'getDefaultUserAgent', args) ?? + ''; + } + @override Future get tRexRunnerHtml async => await rootBundle.loadString( 'packages/flutter_inappwebview/assets/t_rex_runner/t-rex.html'); diff --git a/flutter_inappwebview_web/lib/src/inappwebview_platform.dart b/flutter_inappwebview_web/lib/src/inappwebview_platform.dart index 55d428203..bfe3e6371 100644 --- a/flutter_inappwebview_web/lib/src/inappwebview_platform.dart +++ b/flutter_inappwebview_web/lib/src/inappwebview_platform.dart @@ -2,6 +2,7 @@ import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_pla import 'cookie_manager.dart'; import 'in_app_webview/main.dart'; +import 'web_storage/web_storage.dart'; /// Implementation of [InAppWebViewPlatform] using the Web API. class WebPlatformInAppWebViewPlatform extends InAppWebViewPlatform { @@ -21,6 +22,15 @@ class WebPlatformInAppWebViewPlatform extends InAppWebViewPlatform { return WebPlatformCookieManager(params); } + /// Creates a new empty [WebPlatformCookieManager] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [CookieManager] in `flutter_inappwebview` instead. + @override + WebPlatformCookieManager createPlatformCookieManagerStatic() { + return WebPlatformCookieManager.static(); + } + /// Creates a new [WebPlatformInAppWebViewController]. /// /// This function should only be called by the app-facing package. @@ -53,6 +63,15 @@ class WebPlatformInAppWebViewPlatform extends InAppWebViewPlatform { return WebPlatformInAppWebViewWidget(params); } + /// Creates a new empty [WebPlatformInAppWebViewWidget] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [InAppWebView] in `flutter_inappwebview` instead. + @override + WebPlatformInAppWebViewWidget createPlatformInAppWebViewWidgetStatic() { + return WebPlatformInAppWebViewWidget.static(); + } + /// Creates a new [WebPlatformHeadlessInAppWebView]. /// /// This function should only be called by the app-facing package. @@ -63,4 +82,425 @@ class WebPlatformInAppWebViewPlatform extends InAppWebViewPlatform { ) { return WebPlatformHeadlessInAppWebView(params); } + + /// Creates a new empty [WebPlatformHeadlessInAppWebView] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [HeadlessInAppWebView] in `flutter_inappwebview` instead. + @override + WebPlatformHeadlessInAppWebView createPlatformHeadlessInAppWebViewStatic() { + return WebPlatformHeadlessInAppWebView.static(); + } + + /// Creates a new [WebPlatformWebStorage]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [WebStorage] in `flutter_inappwebview` instead. + @override + WebPlatformWebStorage createPlatformWebStorage( + PlatformWebStorageCreationParams params, + ) { + return WebPlatformWebStorage(params); + } + + /// Creates a new empty [WebPlatformWebStorage] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [WebStorage] in `flutter_inappwebview` instead. + @override + WebPlatformWebStorage createPlatformWebStorageStatic() { + return WebPlatformWebStorage(WebPlatformWebStorageCreationParams( + localStorage: createPlatformLocalStorageStatic(), + sessionStorage: createPlatformSessionStorageStatic())); + } + + /// Creates a new [WebPlatformLocalStorage]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [LocalStorage] in `flutter_inappwebview` instead. + @override + WebPlatformLocalStorage createPlatformLocalStorage( + PlatformLocalStorageCreationParams params, + ) { + return WebPlatformLocalStorage(params); + } + + /// Creates a new empty [WebPlatformLocalStorage] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [LocalStorage] in `flutter_inappwebview` instead. + @override + WebPlatformLocalStorage createPlatformLocalStorageStatic() { + return WebPlatformLocalStorage.defaultStorage(controller: null); + } + + /// Creates a new [WebPlatformSessionStorage]. + /// + /// This function should only be called by the app-facing package. + /// Look at using [SessionStorage] in `flutter_inappwebview` instead. + @override + WebPlatformSessionStorage createPlatformSessionStorage( + PlatformSessionStorageCreationParams params, + ) { + return WebPlatformSessionStorage(params); + } + + /// Creates a new empty [WebPlatformSessionStorage] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [SessionStorage] in `flutter_inappwebview` instead. + @override + WebPlatformSessionStorage createPlatformSessionStorageStatic() { + return WebPlatformSessionStorage.defaultStorage(controller: null); + } + + /// Creates a new empty [PlatformWebStorageManager] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [WebStorageManager] in `flutter_inappwebview` instead. + @override + PlatformWebStorageManager createPlatformWebStorageManagerStatic() { + return _PlatformWebStorageManager.static(); + } + + // ************************************************************************ // + // Create static instances of unsupported classes to be able to call // + // isClassSupported, isMethodSupported, isPropertySupported, etc. // + // static methods without throwing a missing platform implementation // + // exception. // + // ************************************************************************ // + + /// Creates a new empty [PlatformWebViewEnvironment] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [WebViewEnvironment] in `flutter_inappwebview` instead. + @override + PlatformWebViewEnvironment createPlatformWebViewEnvironmentStatic() { + return _PlatformWebViewEnvironment.static(); + } + + /// Creates a new empty [PlatformInAppBrowser] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [InAppBrowser] in `flutter_inappwebview` instead. + @override + PlatformInAppBrowser createPlatformInAppBrowserStatic() { + return _PlatformInAppBrowser.static(); + } + + /// Creates a new empty [PlatformChromeSafariBrowser] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [ChromeSafariBrowser] in `flutter_inappwebview` instead. + PlatformChromeSafariBrowser createPlatformChromeSafariBrowserStatic() { + return _PlatformChromeSafariBrowser.static(); + } + + /// Creates a new empty [PlatformHttpAuthCredentialDatabase] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [HttpAuthCredentialDatabase] in `flutter_inappwebview` instead. + @override + PlatformHttpAuthCredentialDatabase + createPlatformHttpAuthCredentialDatabaseStatic() { + return _PlatformHttpAuthCredentialDatabase.static(); + } + + /// Creates a new empty [PlatformProcessGlobalConfig] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [ProcessGlobalConfig] in `flutter_inappwebview` instead. + @override + PlatformProcessGlobalConfig createPlatformProcessGlobalConfigStatic() { + return _PlatformProcessGlobalConfig.static(); + } + + /// Creates a new empty [PlatformProxyController] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [ProxyController] in `flutter_inappwebview` instead. + @override + PlatformProxyController createPlatformProxyControllerStatic() { + return _PlatformProxyController.static(); + } + + /// Creates a new empty [PlatformServiceWorkerController] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [ServiceWorkerController] in `flutter_inappwebview` instead. + @override + PlatformServiceWorkerController + createPlatformServiceWorkerControllerStatic() { + return _PlatformServiceWorkerController.static(); + } + + /// Creates a new empty [PlatformTracingController] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [TracingController] in `flutter_inappwebview` instead. + @override + PlatformTracingController createPlatformTracingControllerStatic() { + return _PlatformTracingController.static(); + } + + /// Creates a new empty [PlatformFindInteractionController] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [FindInteractionController] in `flutter_inappwebview` instead. + @override + PlatformFindInteractionController + createPlatformFindInteractionControllerStatic() { + return _PlatformFindInteractionController.static(); + } + + /// Creates a new empty [PlatformPrintJobController] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [PrintJobController] in `flutter_inappwebview` instead. + @override + PlatformPrintJobController createPlatformPrintJobControllerStatic() { + return _PlatformPrintJobController.static(); + } + + /// Creates a new empty [PlatformPullToRefreshController] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [PullToRefreshController] in `flutter_inappwebview` instead. + @override + PlatformPullToRefreshController + createPlatformPullToRefreshControllerStatic() { + return _PlatformPullToRefreshController.static(); + } + + /// Creates a new empty [PlatformWebAuthenticationSession] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [WebAuthenticationSession] in `flutter_inappwebview` instead. + @override + PlatformWebAuthenticationSession + createPlatformWebAuthenticationSessionStatic() { + return _PlatformWebAuthenticationSession.static(); + } + + /// Creates a new empty [PlatformWebMessageChannel] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [WebMessageChannel] in `flutter_inappwebview` instead. + @override + PlatformWebMessageChannel createPlatformWebMessageChannelStatic() { + return _PlatformWebMessageChannel.static(); + } + + /// Creates a new empty [PlatformWebMessageListener] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [WebMessageListener] in `flutter_inappwebview` instead. + @override + PlatformWebMessageListener createPlatformWebMessageListenerStatic() { + return _PlatformWebMessageListener.static(); + } +} + +class _PlatformInAppBrowser extends PlatformInAppBrowser { + _PlatformInAppBrowser(PlatformInAppBrowserCreationParams params) + : super.implementation(params); + static final _PlatformInAppBrowser _staticValue = + _PlatformInAppBrowser(const PlatformInAppBrowserCreationParams()); + + factory _PlatformInAppBrowser.static() => _staticValue; +} + +class _PlatformChromeSafariBrowser extends PlatformChromeSafariBrowser { + _PlatformChromeSafariBrowser(PlatformChromeSafariBrowserCreationParams params) + : super.implementation(params); + static final _PlatformChromeSafariBrowser _staticValue = + _PlatformChromeSafariBrowser( + const PlatformChromeSafariBrowserCreationParams()); + + factory _PlatformChromeSafariBrowser.static() => _staticValue; +} + +class _PlatformHttpAuthCredentialDatabase + extends PlatformHttpAuthCredentialDatabase { + _PlatformHttpAuthCredentialDatabase( + PlatformHttpAuthCredentialDatabaseCreationParams params) + : super.implementation(params); + static final _PlatformHttpAuthCredentialDatabase _staticValue = + _PlatformHttpAuthCredentialDatabase( + const PlatformHttpAuthCredentialDatabaseCreationParams()); + + factory _PlatformHttpAuthCredentialDatabase.static() => _staticValue; +} + +class _PlatformProcessGlobalConfig extends PlatformProcessGlobalConfig { + _PlatformProcessGlobalConfig(PlatformProcessGlobalConfigCreationParams params) + : super.implementation(params); + static final _PlatformProcessGlobalConfig _staticValue = + _PlatformProcessGlobalConfig( + const PlatformProcessGlobalConfigCreationParams()); + + factory _PlatformProcessGlobalConfig.static() => _staticValue; +} + +class _PlatformProxyController extends PlatformProxyController { + _PlatformProxyController(PlatformProxyControllerCreationParams params) + : super.implementation(params); + static final _PlatformProxyController _staticValue = + _PlatformProxyController(const PlatformProxyControllerCreationParams()); + + factory _PlatformProxyController.static() => _staticValue; +} + +class _PlatformServiceWorkerController extends PlatformServiceWorkerController { + _PlatformServiceWorkerController( + PlatformServiceWorkerControllerCreationParams params) + : super.implementation(params); + static final _PlatformServiceWorkerController _staticValue = + _PlatformServiceWorkerController( + const PlatformServiceWorkerControllerCreationParams()); + + factory _PlatformServiceWorkerController.static() => _staticValue; + + @override + ServiceWorkerClient? get serviceWorkerClient => throw UnimplementedError(); +} + +class _PlatformTracingController extends PlatformTracingController { + _PlatformTracingController(PlatformTracingControllerCreationParams params) + : super.implementation(params); + static final _PlatformTracingController _staticValue = + _PlatformTracingController( + const PlatformTracingControllerCreationParams()); + + factory _PlatformTracingController.static() => _staticValue; +} + +class _PlatformFindInteractionController + extends PlatformFindInteractionController { + _PlatformFindInteractionController( + PlatformFindInteractionControllerCreationParams params) + : super.implementation(params); + static final _PlatformFindInteractionController _staticValue = + _PlatformFindInteractionController( + const PlatformFindInteractionControllerCreationParams()); + + factory _PlatformFindInteractionController.static() => _staticValue; +} + +class _PlatformPrintJobController extends PlatformPrintJobController { + _PlatformPrintJobController(PlatformPrintJobControllerCreationParams params) + : super.implementation(params); + + static final _PlatformPrintJobController _staticValue = + _PlatformPrintJobController( + const PlatformPrintJobControllerCreationParams(id: '')); + + factory _PlatformPrintJobController.static() => _staticValue; +} + +class _PlatformPullToRefreshController extends PlatformPullToRefreshController { + _PlatformPullToRefreshController( + PlatformPullToRefreshControllerCreationParams params) + : super.implementation(params); + + static final _PlatformPullToRefreshController _staticValue = + _PlatformPullToRefreshController( + PlatformPullToRefreshControllerCreationParams()); + + factory _PlatformPullToRefreshController.static() => _staticValue; +} + +class _PlatformWebAuthenticationSession + extends PlatformWebAuthenticationSession { + _PlatformWebAuthenticationSession( + PlatformWebAuthenticationSessionCreationParams params) + : super.implementation(params); + + static final _PlatformWebAuthenticationSession _staticValue = + _PlatformWebAuthenticationSession( + const PlatformWebAuthenticationSessionCreationParams()); + + factory _PlatformWebAuthenticationSession.static() => _staticValue; +} + +class _PlatformWebMessageChannel extends PlatformWebMessageChannel { + _PlatformWebMessageChannel(PlatformWebMessageChannelCreationParams params) + : super.implementation(params); + + static final _PlatformWebMessageChannel _staticValue = + _PlatformWebMessageChannel(PlatformWebMessageChannelCreationParams( + id: '', + port1: _PlatformWebMessagePort( + const PlatformWebMessagePortCreationParams(index: 0)), + port2: _PlatformWebMessagePort( + const PlatformWebMessagePortCreationParams(index: 1)))); + + factory _PlatformWebMessageChannel.static() => _staticValue; +} + +class _PlatformWebMessageListener extends PlatformWebMessageListener { + _PlatformWebMessageListener(PlatformWebMessageListenerCreationParams params) + : super.implementation(params); + + static final _PlatformWebMessageListener _staticValue = + _PlatformWebMessageListener( + const PlatformWebMessageListenerCreationParams(jsObjectName: '')); + + factory _PlatformWebMessageListener.static() => _staticValue; +} + +class _PlatformWebMessagePort extends PlatformWebMessagePort { + _PlatformWebMessagePort(PlatformWebMessagePortCreationParams params) + : super.implementation(params); + + static final _PlatformWebMessagePort _staticValue = _PlatformWebMessagePort( + const PlatformWebMessagePortCreationParams(index: 0)); + + factory _PlatformWebMessagePort.static() => _staticValue; + + @override + Future close() { + throw UnimplementedError(); + } + + @override + Future postMessage(WebMessage message) { + throw UnimplementedError(); + } + + @override + Future setWebMessageCallback(WebMessageCallback? onMessage) { + throw UnimplementedError(); + } + + @override + Map toJson() { + throw UnimplementedError(); + } + + @override + Map toMap({EnumMethod? enumMethod}) { + throw UnimplementedError(); + } +} + +class _PlatformWebStorageManager extends PlatformWebStorageManager { + _PlatformWebStorageManager(PlatformWebStorageManagerCreationParams params) + : super.implementation(params); + + static final _PlatformWebStorageManager _staticValue = + _PlatformWebStorageManager( + const PlatformWebStorageManagerCreationParams()); + + factory _PlatformWebStorageManager.static() => _staticValue; +} + +class _PlatformWebViewEnvironment extends PlatformWebViewEnvironment { + _PlatformWebViewEnvironment(PlatformWebViewEnvironmentCreationParams params) + : super.implementation(params); + static final _PlatformWebViewEnvironment _staticValue = + _PlatformWebViewEnvironment( + const PlatformWebViewEnvironmentCreationParams()); + + factory _PlatformWebViewEnvironment.static() => _staticValue; } diff --git a/flutter_inappwebview_web/lib/web/headless_inappwebview_manager.dart b/flutter_inappwebview_web/lib/web/headless_inappwebview_manager.dart index 9d0ab7f14..183116513 100644 --- a/flutter_inappwebview_web/lib/web/headless_inappwebview_manager.dart +++ b/flutter_inappwebview_web/lib/web/headless_inappwebview_manager.dart @@ -2,36 +2,27 @@ import 'package:web/web.dart'; import 'package:flutter/services.dart'; import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import 'web_platform_manager.dart'; +import 'in_app_webview_manager.dart'; import 'in_app_web_view_web_element.dart'; import 'headless_in_app_web_view_web_element.dart'; -class HeadlessInAppWebViewManager { +class HeadlessInAppWebViewManager extends ChannelController { static final Map webViews = {}; - static late MethodChannel _sharedChannel; - late BinaryMessenger _messenger; HeadlessInAppWebViewManager({required BinaryMessenger messenger}) { this._messenger = messenger; - HeadlessInAppWebViewManager._sharedChannel = MethodChannel( + channel = MethodChannel( 'com.pichillilorenzo/flutter_headless_inappwebview', const StandardMethodCodec(), _messenger, ); - HeadlessInAppWebViewManager._sharedChannel - .setMethodCallHandler((call) async { - try { - return await handleMethod(call); - } on Error catch (e) { - print(e); - print(e.stackTrace); - } - }); + handler = _handleMethod; + initMethodCallHandler(); } - Future handleMethod(MethodCall call) async { + Future _handleMethod(MethodCall call) async { switch (call.method) { case "run": String id = call.arguments["id"]; @@ -49,7 +40,7 @@ class HeadlessInAppWebViewManager { var webView = InAppWebViewWebElement(viewId: id, messenger: _messenger); var headlessWebView = HeadlessInAppWebViewWebElement( id: id, messenger: _messenger, webView: webView); - WebPlatformManager.webViews.putIfAbsent(id, () => webView); + InAppWebViewManager.webViews.putIfAbsent(id, () => webView); HeadlessInAppWebViewManager.webViews.putIfAbsent(id, () => headlessWebView); prepare(webView, params); headlessWebView.onWebViewCreated(); @@ -77,7 +68,13 @@ class HeadlessInAppWebViewManager { webView.initialFile = params["initialFile"]; webView.initialData = InAppWebViewInitialData.fromMap( params["initialData"]?.cast()); + webView.initialUserScripts = params["initialUserScripts"]; document.body?.append(webView.iframeContainer); webView.prepare(); } + + @override + void dispose() { + disposeChannel(); + } } diff --git a/flutter_inappwebview_web/lib/web/in_app_web_view_web_element.dart b/flutter_inappwebview_web/lib/web/in_app_web_view_web_element.dart index 2e9a114f6..1bd5ed254 100644 --- a/flutter_inappwebview_web/lib/web/in_app_web_view_web_element.dart +++ b/flutter_inappwebview_web/lib/web/in_app_web_view_web_element.dart @@ -1,19 +1,23 @@ import 'dart:async'; -import 'dart:typed_data'; -import 'dart:ui'; +import 'dart:collection'; +import 'dart:convert'; +import 'dart:developer'; +import 'dart:js_interop'; +import 'dart:typed_data' as typed_data; + +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import 'dart:js_interop'; -import 'dart:developer'; import 'package:web/web.dart'; import 'headless_inappwebview_manager.dart'; -import 'web_platform_manager.dart'; +import 'in_app_webview_manager.dart'; import 'js_bridge.dart'; extension on HTMLIFrameElement { // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/csp external set csp(String? value); + external String? get csp; } @@ -26,13 +30,18 @@ class InAppWebViewWebElement implements Disposable { InAppWebViewSettings? initialSettings; URLRequest? initialUrlRequest; InAppWebViewInitialData? initialData; + UnmodifiableListView? initialUserScripts; String? initialFile; String? headlessWebViewId; + final UserContentController userContentController = UserContentController(); + late final int? windowId; InAppWebViewSettings? settings; JSWebView? jsWebView; bool isLoading = false; + late final String _expectedBridgeSecret; + InAppWebViewWebElement( {required dynamic viewId, required BinaryMessenger messenger}) { this._viewId = viewId; @@ -64,8 +73,20 @@ class InAppWebViewWebElement implements Disposable { } }); + try { + _expectedBridgeSecret = window.crypto.randomUUID(); + } catch (e) { + _expectedBridgeSecret = (window.crypto + .getRandomValues(typed_data.Uint32List(5).toJS) as JSUint32Array) + .toDart + .join('-'); + } + jsWebView = flutterInAppWebView?.createFlutterInAppWebView( - _viewId, iframe, iframeContainer); + _viewId is int ? (_viewId as int).toJS : _viewId.toString().toJS, + iframe, + iframeContainer, + _expectedBridgeSecret); } /// Handles method calls over the MethodChannel of this plugin. @@ -176,6 +197,23 @@ class InAppWebViewWebElement implements Disposable { return await canScrollVertically(); case "canScrollHorizontally": return await canScrollHorizontally(); + case "addUserScript": + UserScript userScript = UserScript.fromMap( + call.arguments["userScript"].cast())!; + userContentController.addUserOnlyScript(userScript); + break; + case "removeUserScript": + UserScript userScript = UserScript.fromMap( + call.arguments["userScript"].cast())!; + userContentController.removeUserOnlyScript(userScript); + break; + case "removeUserScriptsByGroupName": + String groupName = call.arguments["groupName"]; + userContentController.removeUserOnlyScriptsByGroupName(groupName); + break; + case "removeAllUserScripts": + userContentController.removeAllUserOnlyScripts(); + break; case "dispose": dispose(); break; @@ -206,9 +244,13 @@ class InAppWebViewWebElement implements Disposable { initialUrlRequest = webView.initialUrlRequest; initialData = webView.initialData; initialFile = webView.initialFile; + initialUserScripts = webView.initialUserScripts; jsWebView = flutterInAppWebView?.createFlutterInAppWebView( - _viewId, iframe, iframeContainer); + _viewId is int ? (_viewId as int).toJS : _viewId.toString().toJS, + iframe, + iframeContainer, + _expectedBridgeSecret); } } } @@ -230,6 +272,8 @@ class InAppWebViewWebElement implements Disposable { iframe.referrerPolicy; iframe.name = settings!.iframeName ?? iframe.name; iframe.csp = settings!.iframeCsp ?? iframe.csp; + iframe.role = settings!.iframeRole ?? iframe.role; + iframe.ariaHidden = settings!.iframeAriaHidden ?? iframe.ariaHidden; if (settings!.iframeSandbox != null && settings!.iframeSandbox != Sandbox.ALLOW_ALL) { @@ -244,11 +288,20 @@ class InAppWebViewWebElement implements Disposable { } } + if (initialUserScripts != null) { + userContentController.addUserOnlyScripts(initialUserScripts!.toList()); + } + jsWebView?.prepare(settings?.toMap().jsify()); } void makeInitialLoad() async { - if (initialUrlRequest != null) { + if (windowId != null) { + if (InAppWebViewManager.windowActions.containsKey(windowId!)) { + final createWindowAction = InAppWebViewManager.windowActions[windowId!]; + loadUrl(urlRequest: createWindowAction!.request); + } + } else if (initialUrlRequest != null) { loadUrl(urlRequest: initialUrlRequest!); } else if (initialData != null) { loadData(data: initialData!.data, mimeType: initialData!.mimeType); @@ -470,6 +523,12 @@ class InAppWebViewWebElement implements Disposable { if (settings!.iframeCsp != newSettings.iframeCsp) { iframe.csp = newSettings.iframeCsp; } + if (settings!.iframeRole != newSettings.iframeRole) { + iframe.role = newSettings.iframeRole; + } + if (settings!.iframeAriaHidden != newSettings.iframeAriaHidden) { + iframe.ariaHidden = newSettings.iframeAriaHidden; + } if (settings!.iframeSandbox != newSettings.iframeSandbox) { var sandbox = newSettings.iframeSandbox; @@ -540,7 +599,7 @@ class InAppWebViewWebElement implements Disposable { } Future onCreateWindow( - int windowId, String url, String? target, String? windowFeatures) async { + String url, String? target, String? windowFeatures) async { Map windowFeaturesMap = {}; List features = windowFeatures?.split(",") ?? []; for (var feature in features) { @@ -556,13 +615,29 @@ class InAppWebViewWebElement implements Disposable { } } - var obj = { + final windowId = InAppWebViewManager.windowAutoincrementId; + InAppWebViewManager.windowAutoincrementId++; + + final createWindowAction = CreateWindowAction.fromMap({ "windowId": windowId, "isForMainFrame": true, "request": {"url": url, "method": "GET"}, "windowFeatures": windowFeaturesMap - }; - return await _channel?.invokeMethod("onCreateWindow", obj); + }); + + InAppWebViewManager.windowActions[windowId] = createWindowAction!; + final handledByClient = await _channel?.invokeMethod( + "onCreateWindow", createWindowAction.toMap()) ?? + false; + if (!handledByClient && + InAppWebViewManager.windowActions.containsKey(windowId)) { + InAppWebViewManager.windowActions.remove(windowId); + } + return handledByClient; + } + + void onCloseWindow() async { + await _channel?.invokeMethod("onCloseWindow"); } void onWindowFocus() async { @@ -607,13 +682,106 @@ class InAppWebViewWebElement implements Disposable { await _channel?.invokeMethod("onInjectedScriptError", [id]); } + Future onCallJsHandler( + String handlerName, Map data) async { + final String bridgeSecret = data["_bridgeSecret"]; + final String origin = data["origin"]; + + if (_expectedBridgeSecret != bridgeSecret) { + if (kDebugMode) { + print( + "Bridge access attempt with wrong secret token, possibly from malicious code from origin: " + + origin); + } + return null; + } + + var isOriginAllowed = false; + var javaScriptHandlersOriginAllowList = + settings?.javaScriptHandlersOriginAllowList; + if (javaScriptHandlersOriginAllowList != null) { + for (String allowedOrigin in javaScriptHandlersOriginAllowList) { + if (RegExp(allowedOrigin).hasMatch(origin)) { + isOriginAllowed = true; + break; + } + } + } else { + // origin is by default allowed if the allow list is null + isOriginAllowed = true; + } + if (!isOriginAllowed) { + if (kDebugMode) { + print("Bridge access attempt from an origin not allowed: " + origin); + } + return null; + } + + var obj = {"handlerName": handlerName, "data": data}; + final result = await _channel?.invokeMethod("onCallJsHandler", obj); + return result != null ? jsonDecode(result) : null; + } + @override void dispose() { _channel?.setMethodCallHandler(null); _channel = null; + if (windowId != null && + InAppWebViewManager.windowActions.containsKey(windowId)) { + InAppWebViewManager.windowActions.remove(windowId); + } iframeContainer.remove(); - if (WebPlatformManager.webViews.containsKey(_viewId)) { - WebPlatformManager.webViews.remove(_viewId); + if (InAppWebViewManager.webViews.containsKey(_viewId)) { + InAppWebViewManager.webViews.remove(_viewId); + } + } +} + +class UserContentController implements Disposable { + final Map> _userOnlyScripts = { + UserScriptInjectionTime.AT_DOCUMENT_START: [], + UserScriptInjectionTime.AT_DOCUMENT_END: [], + }; + + UserContentController(); + + List getUserOnlyScriptsAt(UserScriptInjectionTime injectionTime) { + return _userOnlyScripts[injectionTime]!; + } + + void addUserOnlyScript(UserScript userScript) { + _userOnlyScripts[userScript.injectionTime]!.add(userScript); + } + + void addUserOnlyScripts(List userScripts) { + for (var userScript in userScripts) { + addUserOnlyScript(userScript); } } + + bool removeUserOnlyScript(UserScript userScript) { + return _userOnlyScripts[userScript.injectionTime]!.remove(userScript); + } + + UserScript removeUserOnlyScriptAt( + int index, UserScriptInjectionTime injectionTime) { + return _userOnlyScripts[injectionTime]!.removeAt(index); + } + + void removeUserOnlyScriptsByGroupName(String groupName) { + for (var injectionTime in UserScriptInjectionTime.values) { + _userOnlyScripts[injectionTime]! + .removeWhere((userScript) => userScript.groupName == groupName); + } + } + + removeAllUserOnlyScripts() { + _userOnlyScripts[UserScriptInjectionTime.AT_DOCUMENT_START]!.clear(); + _userOnlyScripts[UserScriptInjectionTime.AT_DOCUMENT_END]!.clear(); + } + + @override + void dispose() { + removeAllUserOnlyScripts(); + } } diff --git a/flutter_inappwebview_web/lib/web/in_app_webview_manager.dart b/flutter_inappwebview_web/lib/web/in_app_webview_manager.dart new file mode 100644 index 000000000..34cb6e360 --- /dev/null +++ b/flutter_inappwebview_web/lib/web/in_app_webview_manager.dart @@ -0,0 +1,47 @@ +import 'dart:async'; +import 'package:flutter/services.dart'; +import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; +import 'package:web/web.dart'; + +class InAppWebViewManager extends ChannelController { + static final Map webViews = {}; + static final Map windowActions = {}; + static int windowAutoincrementId = 0; + static String javaScriptBridgeName = "flutter_inappwebview"; + late BinaryMessenger _messenger; + + InAppWebViewManager({required BinaryMessenger messenger}) { + this._messenger = messenger; + channel = MethodChannel( + 'com.pichillilorenzo/flutter_inappwebview_manager', + const StandardMethodCodec(), + _messenger, + ); + handler = _handleMethod; + initMethodCallHandler(); + } + + Future _handleMethod(MethodCall call) async { + switch (call.method) { + case "getDefaultUserAgent": + return getDefaultUserAgent(); + case "setJavaScriptBridgeName": + javaScriptBridgeName = call.arguments["bridgeName"]; + break; + case "getJavaScriptBridgeName": + return javaScriptBridgeName; + default: + throw UnimplementedError("Unimplemented ${call.method} method"); + } + return null; + } + + String getDefaultUserAgent() { + return window.navigator.userAgent; + } + + @override + void dispose() { + disposeChannel(); + } +} diff --git a/flutter_inappwebview_web/lib/web/js_bridge.dart b/flutter_inappwebview_web/lib/web/js_bridge.dart index 31b0a05ea..ed94ae114 100644 --- a/flutter_inappwebview_web/lib/web/js_bridge.dart +++ b/flutter_inappwebview_web/lib/web/js_bridge.dart @@ -40,15 +40,23 @@ extension type JSWebView._(JSObject _) implements JSObject { external JSSize getSize(); } -@JS('window.flutter_inappwebview') +@JS('window.flutter_inappwebview_plugin') external FlutterInAppWebViewBridge? get flutterInAppWebView; extension type FlutterInAppWebViewBridge._(JSObject _) implements JSObject { - external JSObject webViews; external JSWebView createFlutterInAppWebView( - JSAny viewId, HTMLIFrameElement iframe, HTMLDivElement iframeContainer); + JSAny viewId, + HTMLIFrameElement iframe, + HTMLDivElement iframeContainer, + String bridgeSecret); external JSString getCookieExpirationDate(num timestamp); - /// Allows assigning a function to be callable from `window.flutter_inappwebview.nativeCommunication()` - external JSFunction nativeCommunication; + external JSFunction nativeAsyncCommunication; + external JSFunction nativeSyncCommunication; } + +@JS('Object.freeze') +external JSObject Object_freeze(JSObject obj); + +@JS('Object.isFrozen') +external JSBoolean Object_isFrozen(JSObject obj); diff --git a/flutter_inappwebview_web/lib/web/web_platform.dart b/flutter_inappwebview_web/lib/web/web_platform.dart index 5e51c262d..09d83f0dc 100644 --- a/flutter_inappwebview_web/lib/web/web_platform.dart +++ b/flutter_inappwebview_web/lib/web/web_platform.dart @@ -1,13 +1,17 @@ import 'dart:async'; +import 'dart:convert'; import 'dart:js_interop'; import 'dart:ui_web' as ui_web; -import '../src/inappwebview_platform.dart'; -import 'headless_inappwebview_manager.dart'; -import 'js_bridge.dart'; -import 'web_platform_manager.dart'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; import 'package:flutter_web_plugins/flutter_web_plugins.dart'; +import '../src/inappwebview_platform.dart'; +import 'headless_inappwebview_manager.dart'; import 'in_app_web_view_web_element.dart'; +import 'in_app_webview_manager.dart'; +import 'js_bridge.dart'; import 'platform_util.dart'; /// Builds an iframe based WebView. @@ -20,7 +24,7 @@ class InAppWebViewFlutterPlugin { 'com.pichillilorenzo/flutter_inappwebview', (int viewId) { var webView = InAppWebViewWebElement(viewId: viewId, messenger: registrar); - WebPlatformManager.webViews.putIfAbsent(viewId, () => webView); + InAppWebViewManager.webViews.putIfAbsent(viewId, () => webView); return webView.iframeContainer; }); } @@ -32,83 +36,153 @@ class InAppWebViewFlutterPlugin { // ignore: unused_local_variable final platformUtil = PlatformUtil(messenger: registrar); // ignore: unused_local_variable + final inAppWebViewManager = InAppWebViewManager(messenger: registrar); + // ignore: unused_local_variable final headlessManager = HeadlessInAppWebViewManager(messenger: registrar); - flutterInAppWebView?.nativeCommunication = ((String method, JSAny viewId, - [JSArray? args]) => - _dartNativeCommunication(method, viewId, args?.toDart).toJS).toJS; + if (flutterInAppWebView != null) { + if (!Object_isFrozen(flutterInAppWebView!).toDart) { + flutterInAppWebView!.nativeAsyncCommunication = + ((JSString method, JSAny viewId, [JSArray? args]) { + return _dartNativeAsyncCommunication( + method.toDart, viewId, args?.toDart) + .then((value) => value?.toJS) + .toJS; + }).toJS; + flutterInAppWebView!.nativeSyncCommunication = ((JSString method, + JSAny viewId, [JSArray? args]) => + _dartNativeSyncCommunication(method.toDart, viewId, args?.toDart) + ?.toJS).toJS; + Object_freeze(flutterInAppWebView!); + } + } else { + if (kDebugMode) { + print("Error: window.flutter_inappwebview_plugin is not available!"); + } + } } } -Future _dartNativeCommunication(String method, dynamic viewId, +Future _dartNativeAsyncCommunication(String method, dynamic viewId, [List? args]) async { - if (WebPlatformManager.webViews.containsKey(viewId)) { + if (InAppWebViewManager.webViews.containsKey(viewId)) { var webViewHtmlElement = - WebPlatformManager.webViews[viewId] as InAppWebViewWebElement; - switch (method) { - case 'onLoadStart': - String url = args![0]; - webViewHtmlElement.onLoadStart(url); - break; - case 'onLoadStop': - String url = args![0]; - webViewHtmlElement.onLoadStop(url); - break; - case 'onUpdateVisitedHistory': - String url = args![0]; - webViewHtmlElement.onUpdateVisitedHistory(url); - break; - case 'onScrollChanged': - int x = (args![0] as double).toInt(); - int y = (args[1] as double).toInt(); - webViewHtmlElement.onScrollChanged(x, y); - break; - case 'onConsoleMessage': - String type = args![0]; - String? message = args[1]; - webViewHtmlElement.onConsoleMessage(type, message); - break; - case 'onCreateWindow': - int windowId = args![0]; - String url = args[1] ?? 'about:blank'; - String? target = args[2]; - String? windowFeatures = args[3]; - return (await webViewHtmlElement.onCreateWindow( - windowId, url, target, windowFeatures)) - ?.toJS; - case 'onWindowFocus': - webViewHtmlElement.onWindowFocus(); - break; - case 'onWindowBlur': - webViewHtmlElement.onWindowBlur(); - break; - case 'onPrintRequest': - String? url = args![0]; - webViewHtmlElement.onPrintRequest(url); - break; - case 'onEnterFullscreen': - webViewHtmlElement.onEnterFullscreen(); - break; - case 'onExitFullscreen': - webViewHtmlElement.onExitFullscreen(); - break; - case 'onTitleChanged': - String? title = args![0]; - webViewHtmlElement.onTitleChanged(title); - break; - case 'onZoomScaleChanged': - double oldScale = args![0]; - double newScale = args[1]; - webViewHtmlElement.onZoomScaleChanged(oldScale, newScale); - break; - case 'onInjectedScriptLoaded': - String id = args![0]; - webViewHtmlElement.onInjectedScriptLoaded(id); - break; - case 'onInjectedScriptError': - String id = args![0]; - webViewHtmlElement.onInjectedScriptError(id); - break; + InAppWebViewManager.webViews[viewId] as InAppWebViewWebElement; + var result = null; + try { + switch (method) { + case 'onCreateWindow': + String url = args![0] ?? 'about:blank'; + String? target = args[1]; + String? windowFeatures = args[2]; + result = await webViewHtmlElement.onCreateWindow( + url, target, windowFeatures); + break; + case 'onCallJsHandler': + String handlerName = args![0]; + Map data = jsonDecode(args[1]); + result = await webViewHtmlElement.onCallJsHandler(handlerName, data); + break; + default: + throw UnimplementedError("Method '$method' not implemented"); + } + return result != null ? jsonEncode(result) : null; + } catch (e, stacktrace) { + if (!(e is UnimplementedError) && kDebugMode) { + print("$e\n$stacktrace"); + } + throw e; } } return null; } + +String? _dartNativeSyncCommunication(String method, dynamic viewId, + [List? args]) { + if (InAppWebViewManager.webViews.containsKey(viewId)) { + var webViewHtmlElement = + InAppWebViewManager.webViews[viewId] as InAppWebViewWebElement; + var result = null; + + try { + switch (method) { + case 'onLoadStart': + String url = args![0]; + webViewHtmlElement.onLoadStart(url); + break; + case 'onLoadStop': + String url = args![0]; + webViewHtmlElement.onLoadStop(url); + break; + case 'onUpdateVisitedHistory': + String url = args![0]; + webViewHtmlElement.onUpdateVisitedHistory(url); + break; + case 'onScrollChanged': + int x = (args![0] as double).toInt(); + int y = (args[1] as double).toInt(); + webViewHtmlElement.onScrollChanged(x, y); + break; + case 'onConsoleMessage': + String type = args![0]; + String? message = args[1]; + webViewHtmlElement.onConsoleMessage(type, message); + break; + case 'onWindowFocus': + webViewHtmlElement.onWindowFocus(); + break; + case 'onWindowBlur': + webViewHtmlElement.onWindowBlur(); + break; + case 'onPrintRequest': + String? url = args![0]; + webViewHtmlElement.onPrintRequest(url); + break; + case 'onEnterFullscreen': + webViewHtmlElement.onEnterFullscreen(); + break; + case 'onExitFullscreen': + webViewHtmlElement.onExitFullscreen(); + break; + case 'onTitleChanged': + String? title = args![0]; + webViewHtmlElement.onTitleChanged(title); + break; + case 'onZoomScaleChanged': + double oldScale = args![0]; + double newScale = args[1]; + webViewHtmlElement.onZoomScaleChanged(oldScale, newScale); + break; + case 'onInjectedScriptLoaded': + String id = args![0]; + webViewHtmlElement.onInjectedScriptLoaded(id); + break; + case 'onInjectedScriptError': + String id = args![0]; + webViewHtmlElement.onInjectedScriptError(id); + break; + case 'onCloseWindow': + webViewHtmlElement.onCloseWindow(); + break; + case 'getUserOnlyScriptsAt': + final injectionTime = + UserScriptInjectionTime.fromNativeValue(args![0]); + result = webViewHtmlElement.userContentController + .getUserOnlyScriptsAt(injectionTime!); + break; + case 'getJavaScriptBridgeName': + result = InAppWebViewManager.javaScriptBridgeName; + break; + default: + throw UnimplementedError("Method '$method' not implemented"); + } + } catch (e, stacktrace) { + if (!(e is UnimplementedError) && kDebugMode) { + print("$e\n$stacktrace"); + } + throw e; + } + + return result != null ? jsonEncode(result) : null; + } + return null; +} diff --git a/flutter_inappwebview_web/lib/web/web_platform_manager.dart b/flutter_inappwebview_web/lib/web/web_platform_manager.dart deleted file mode 100644 index 13cba5010..000000000 --- a/flutter_inappwebview_web/lib/web/web_platform_manager.dart +++ /dev/null @@ -1,3 +0,0 @@ -abstract class WebPlatformManager { - static final Map webViews = {}; -} diff --git a/flutter_inappwebview_web/pubspec.yaml b/flutter_inappwebview_web/pubspec.yaml index d6557020c..e11dd9823 100644 --- a/flutter_inappwebview_web/pubspec.yaml +++ b/flutter_inappwebview_web/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview_web description: Web implementation of the flutter_inappwebview plugin. -version: 1.1.2 +version: 1.2.0-beta.3 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_web issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues @@ -23,7 +23,8 @@ dependencies: flutter_web_plugins: sdk: flutter web: ^1.0.0 - flutter_inappwebview_platform_interface: ^1.3.0 + flutter_inappwebview_platform_interface: #^1.4.0-beta.3 + path: ../flutter_inappwebview_platform_interface dev_dependencies: flutter_test: diff --git a/flutter_inappwebview_windows/CHANGELOG.md b/flutter_inappwebview_windows/CHANGELOG.md index a1051a195..a49400a37 100644 --- a/flutter_inappwebview_windows/CHANGELOG.md +++ b/flutter_inappwebview_windows/CHANGELOG.md @@ -1,3 +1,40 @@ +## 0.7.0-beta.3 + +- Updated flutter_inappwebview_platform_interface version to ^1.4.0-beta.3 +- Merged "windows: fix WebViewEnvironment dispose crash" [#2433](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2433) (thanks to [GooRingX](https://github.com/GooRingX)) +- Merged "fix #2484, Remove not-empty assert for Cookie.value" [#2486](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2486) (thanks to [laishere](https://github.com/laishere)) +- Merged "Prevent Unpredictable Close On Windows" [#2543](https://github.com/pichillilorenzo/flutter_inappwebview/pull/2543) (thanks to [momadvisor](https://github.com/momadvisor)) + +## 0.7.0-beta.2 + +- Updated flutter_inappwebview_platform_interface version to ^1.4.0-beta.2 +- Updated Microsoft.Web.WebView2 SDK version from `1.0.2792.45` to `1.0.2849.39` +- Implemented `disableDefaultErrorPage`, `statusBarEnabled`, `browserAcceleratorKeysEnabled`, `generalAutofillEnabled`, `passwordAutosaveEnabled`, `isPinchZoomEnabled`, `allowsBackForwardNavigationGestures`, `hiddenPdfToolbarItems`, `reputationCheckingRequired`, `nonClientRegionSupportEnabled` properties of `InAppWebViewSettings` +- Implemented `isInterfaceSupported`, `getProcessInfos`, `getFailureReportFolderPath` WebViewEnvironment methods +- Implemented `isInterfaceSupported`, `getZoomScale` InAppWebViewController method +- Implemented `onDownloadStarting`, `onAcceleratorKeyPressed` WebView event +- Implemented `exclusiveUserDataFolderAccess`, `isCustomCrashReportingEnabled`, `enableTrackingPrevention`, `areBrowserExtensionsEnabled`, `channelSearchKind`, `releaseChannels`, `scrollbarStyle` properties of `WebViewEnvironmentSettings` +- Implemented `onNewBrowserVersionAvailable`, `onBrowserProcessExited`, `onProcessInfosChanged` WebViewEnvironment events +- Send mouse leave region event to native view +- Fixed wrong channel name when creating a `WebViewEnvironment` instance +- Fixed "[Windows] Has an overlay on the desktop when the application is minimized" [#2402](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2402) +- Fixed "[Windows] missing implementation of onPermissionRequest event will cause crash when requested by the webpage" [#2404](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2404) +- Fixed "Windows: getCookies return empty list" [#2314](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2314) + +## 0.7.0-beta.1 + +- Updated flutter_inappwebview_platform_interface version to ^1.4.0-beta.1 +- Updated `scrollMultiplier` default value from 6 to 1 +- Added support for `UserScript.allowedOriginRules` and `UserScript.forMainFrameOnly` parameters +- Implemented `onReceivedHttpAuthRequest`, `onReceivedClientCertRequest`, `onReceivedServerTrustAuthRequest`, `onRenderProcessGone`, `onRenderProcessUnresponsive`, `onWebContentProcessDidTerminate`, `onProcessFailed` WebView events +- Implemented `clearSslPreferences` WebView method +- Fixed `get_optional_fl_map_value` implementation in `utils/flutter.h` +- Fixed "Error in transparentBackground handling in Windows" [#2391](https://github.com/pichillilorenzo/flutter_inappwebview/issues/2391) + +## 0.6.0 + +- Updated code to support multiple flutter windows + ## 0.5.0+2 - Fixed `InAppWebViewController.callAsyncJavaScript` not working with JSON objects diff --git a/flutter_inappwebview_windows/example/pubspec.lock b/flutter_inappwebview_windows/example/pubspec.lock index 83bd88ac0..685563839 100644 --- a/flutter_inappwebview_windows/example/pubspec.lock +++ b/flutter_inappwebview_windows/example/pubspec.lock @@ -78,26 +78,24 @@ packages: flutter_inappwebview_internal_annotations: dependency: transitive description: - name: flutter_inappwebview_internal_annotations - sha256: "5f80fd30e208ddded7dbbcd0d569e7995f9f63d45ea3f548d8dd4c0b473fb4c8" - url: "https://pub.dev" - source: hosted - version: "1.1.1" + path: "../../dev_packages/flutter_inappwebview_internal_annotations" + relative: true + source: path + version: "1.3.0" flutter_inappwebview_platform_interface: dependency: transitive description: - name: flutter_inappwebview_platform_interface - sha256: "6862f4e08aa8f6136762e022c9c1edafb18c1dc3beb03052f2f3f2a48605a182" - url: "https://pub.dev" - source: hosted - version: "1.3.0" + path: "../../flutter_inappwebview_platform_interface" + relative: true + source: path + version: "1.4.0-beta.3" flutter_inappwebview_windows: dependency: "direct main" description: path: ".." relative: true source: path - version: "0.5.0" + version: "0.7.0-beta.3" flutter_lints: dependency: "direct dev" description: diff --git a/flutter_inappwebview_windows/lib/src/cookie_manager.dart b/flutter_inappwebview_windows/lib/src/cookie_manager.dart index 1da14b0b7..47ebdac69 100644 --- a/flutter_inappwebview_windows/lib/src/cookie_manager.dart +++ b/flutter_inappwebview_windows/lib/src/cookie_manager.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; - import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; import 'webview_environment/webview_environment.dart'; @@ -49,6 +48,13 @@ class WindowsCookieManager extends PlatformCookieManager initMethodCallHandler(); } + static final WindowsCookieManager _staticValue = + WindowsCookieManager(WindowsCookieManagerCreationParams()); + + factory WindowsCookieManager.static() { + return _staticValue; + } + static WindowsCookieManager? _instance; ///Gets the [WindowsCookieManager] shared instance. @@ -89,7 +95,6 @@ class WindowsCookieManager extends PlatformCookieManager PlatformInAppWebViewController? webViewController}) async { assert(url.toString().isNotEmpty); assert(name.isNotEmpty); - assert(value.isNotEmpty); assert(path.isNotEmpty); Map args = {}; @@ -105,6 +110,7 @@ class WindowsCookieManager extends PlatformCookieManager args.putIfAbsent('sameSite', () => sameSite?.toNativeValue()); args.putIfAbsent( 'webViewEnvironmentId', () => params.webViewEnvironment?.id); + args.putIfAbsent('webViewId', () => webViewController?.id); return await channel?.invokeMethod('setCookie', args) ?? false; } @@ -123,6 +129,7 @@ class WindowsCookieManager extends PlatformCookieManager args.putIfAbsent('url', () => url.toString()); args.putIfAbsent( 'webViewEnvironmentId', () => params.webViewEnvironment?.id); + args.putIfAbsent('webViewId', () => webViewController?.id); List cookieListMap = await channel?.invokeMethod('getCookies', args) ?? []; cookieListMap = cookieListMap.cast>(); @@ -157,6 +164,7 @@ class WindowsCookieManager extends PlatformCookieManager args.putIfAbsent('url', () => url.toString()); args.putIfAbsent( 'webViewEnvironmentId', () => params.webViewEnvironment?.id); + args.putIfAbsent('webViewId', () => webViewController?.id); List cookies = await channel?.invokeMethod('getCookies', args) ?? []; cookies = cookies.cast>(); @@ -197,6 +205,7 @@ class WindowsCookieManager extends PlatformCookieManager args.putIfAbsent('path', () => path); args.putIfAbsent( 'webViewEnvironmentId', () => params.webViewEnvironment?.id); + args.putIfAbsent('webViewId', () => webViewController?.id); return await channel?.invokeMethod('deleteCookie', args) ?? false; } @@ -216,6 +225,7 @@ class WindowsCookieManager extends PlatformCookieManager args.putIfAbsent('path', () => path); args.putIfAbsent( 'webViewEnvironmentId', () => params.webViewEnvironment?.id); + args.putIfAbsent('webViewId', () => webViewController?.id); return await channel?.invokeMethod('deleteCookies', args) ?? false; } diff --git a/flutter_inappwebview_windows/lib/src/in_app_webview/custom_platform_view.dart b/flutter_inappwebview_windows/lib/src/in_app_webview/custom_platform_view.dart index d4594ca53..dbffdd7f3 100644 --- a/flutter_inappwebview_windows/lib/src/in_app_webview/custom_platform_view.dart +++ b/flutter_inappwebview_windows/lib/src/in_app_webview/custom_platform_view.dart @@ -5,6 +5,7 @@ import 'dart:ui'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; +import '../platform_util.dart'; import '_static_channel.dart'; const Map _cursors = { @@ -55,7 +56,15 @@ enum PointerButton { none, primary, secondary, tertiary } /// Pointer Event kind // Order must match InAppWebViewPointerEventKind (see in_app_webview.h) -enum InAppWebViewPointerEventKind { activate, down, enter, leave, up, update } +enum InAppWebViewPointerEventKind { + activate, + down, + enter, + leave, + up, + update, + cancel +} /// Attempts to translate a button constant such as [kPrimaryMouseButton] /// to a [PointerButton] @@ -193,13 +202,14 @@ class CustomPlatformViewController } /// Indicates whether the specified [button] is currently down. - Future _setPointerButtonState(PointerButton button, bool isDown) async { + Future _setPointerButtonState( + InAppWebViewPointerEventKind kind, PointerButton button) async { if (_isDisposed) { return; } assert(value.isInitialized); return _methodChannel.invokeMethod('setPointerButton', - {'button': button.index, 'isDown': isDown}); + {'kind': kind.index, 'button': button.index}); } /// Sets the horizontal and vertical scroll delta. @@ -259,7 +269,8 @@ class CustomPlatformView extends StatefulWidget { _CustomPlatformViewState createState() => _CustomPlatformViewState(); } -class _CustomPlatformViewState extends State { +class _CustomPlatformViewState extends State + with PlatformUtilListener { final GlobalKey _key = GlobalKey(); final _downButtons = {}; @@ -272,10 +283,16 @@ class _CustomPlatformViewState extends State { StreamSubscription? _cursorSubscription; + late final AppLifecycleListener _listener; + + PlatformUtil _platformUtil = PlatformUtil.instance(); + @override void initState() { super.initState(); + _platformUtil.addListener(this); + _controller.initialize( onPlatformViewCreated: (id) { widget.onPlatformViewCreated?.call(id); @@ -283,6 +300,14 @@ class _CustomPlatformViewState extends State { }, arguments: widget.creationParams); + _listener = AppLifecycleListener(onStateChange: (state) { + if ([AppLifecycleState.resumed, AppLifecycleState.hidden] + .contains(state)) { + _reportSurfaceSize(); + _reportWidgetPosition(); + } + }); + // Report initial surface size and widget position WidgetsBinding.instance.addPostFrameCallback((_) { _reportSurfaceSize(); @@ -296,6 +321,12 @@ class _CustomPlatformViewState extends State { }); } + @override + void onWindowMove() { + _reportSurfaceSize(); + _reportWidgetPosition(); + } + @override Widget build(BuildContext context) { return Focus( @@ -352,7 +383,8 @@ class _CustomPlatformViewState extends State { } final button = _getButton(ev.buttons); _downButtons[ev.pointer] = button; - _controller._setPointerButtonState(button, true); + _controller._setPointerButtonState( + InAppWebViewPointerEventKind.down, button); }, onPointerUp: (ev) { _pointerKind = ev.kind; @@ -367,14 +399,16 @@ class _CustomPlatformViewState extends State { } final button = _downButtons.remove(ev.pointer); if (button != null) { - _controller._setPointerButtonState(button, false); + _controller._setPointerButtonState( + InAppWebViewPointerEventKind.up, button); } }, onPointerCancel: (ev) { _pointerKind = ev.kind; final button = _downButtons.remove(ev.pointer); if (button != null) { - _controller._setPointerButtonState(button, false); + _controller._setPointerButtonState( + InAppWebViewPointerEventKind.cancel, button); } }, onPointerMove: (ev) { @@ -402,6 +436,16 @@ class _CustomPlatformViewState extends State { }, child: MouseRegion( cursor: _cursor, + onEnter: (ev) { + final button = _getButton(ev.buttons); + _controller._setPointerButtonState( + InAppWebViewPointerEventKind.enter, button); + }, + onExit: (ev) { + final button = _getButton(ev.buttons); + _controller._setPointerButtonState( + InAppWebViewPointerEventKind.leave, button); + }, child: Texture( textureId: _controller._textureId, filterQuality: widget.filterQuality, @@ -432,8 +476,10 @@ class _CustomPlatformViewState extends State { @override void dispose() { super.dispose(); + _platformUtil.removeListener(this); _cursorSubscription?.cancel(); _controller.dispose(); _focusNode.dispose(); + _listener.dispose(); } } diff --git a/flutter_inappwebview_windows/lib/src/in_app_webview/headless_in_app_webview.dart b/flutter_inappwebview_windows/lib/src/in_app_webview/headless_in_app_webview.dart index b46a23558..e0f3f29d1 100644 --- a/flutter_inappwebview_windows/lib/src/in_app_webview/headless_in_app_webview.dart +++ b/flutter_inappwebview_windows/lib/src/in_app_webview/headless_in_app_webview.dart @@ -33,8 +33,10 @@ class WindowsHeadlessInAppWebViewCreationParams super.shouldOverrideUrlLoading, super.onLoadResource, super.onScrollChanged, - @Deprecated('Use onDownloadStartRequest instead') super.onDownloadStart, + @Deprecated('Use onDownloadStarting instead') super.onDownloadStart, + @Deprecated('Use onDownloadStarting instead') super.onDownloadStartRequest, + super.onDownloadStarting, @Deprecated('Use onLoadResourceWithCustomScheme instead') super.onLoadResourceCustomScheme, super.onLoadResourceWithCustomScheme, @@ -153,6 +155,7 @@ class WindowsHeadlessInAppWebViewCreationParams onScrollChanged: params.onScrollChanged, onDownloadStart: params.onDownloadStart, onDownloadStartRequest: params.onDownloadStartRequest, + onDownloadStarting: params.onDownloadStarting, onLoadResourceCustomScheme: params.onLoadResourceCustomScheme, onLoadResourceWithCustomScheme: params.onLoadResourceWithCustomScheme, @@ -276,6 +279,13 @@ class WindowsHeadlessInAppWebView extends PlatformHeadlessInAppWebView id = IdGenerator.generate(); } + static final WindowsHeadlessInAppWebView _staticValue = + WindowsHeadlessInAppWebView(WindowsHeadlessInAppWebViewCreationParams()); + + factory WindowsHeadlessInAppWebView.static() { + return _staticValue; + } + @override WindowsInAppWebViewController? get webViewController => _webViewController; @@ -368,13 +378,24 @@ class WindowsHeadlessInAppWebView extends PlatformHeadlessInAppWebView if (params.onLoadResource != null && settings.useOnLoadResource == null) { settings.useOnLoadResource = true; } - if (params.onDownloadStartRequest != null && + if ((params.onDownloadStartRequest != null || + params.onDownloadStarting != null) && settings.useOnDownloadStart == null) { settings.useOnDownloadStart = true; } - if (params.shouldInterceptAjaxRequest != null && - settings.useShouldInterceptAjaxRequest == null) { - settings.useShouldInterceptAjaxRequest = true; + if ((params.shouldInterceptAjaxRequest != null || + params.onAjaxProgress != null || + params.onAjaxReadyStateChange != null)) { + if (settings.useShouldInterceptAjaxRequest == null) { + settings.useShouldInterceptAjaxRequest = true; + } + if (params.onAjaxReadyStateChange != null && + settings.useOnAjaxReadyStateChange == null) { + settings.useOnAjaxReadyStateChange = true; + } + if (params.onAjaxProgress != null && settings.useOnAjaxProgress == null) { + settings.useOnAjaxProgress = true; + } } if (params.shouldInterceptFetchRequest != null && settings.useShouldInterceptFetchRequest == null) { diff --git a/flutter_inappwebview_windows/lib/src/in_app_webview/in_app_webview.dart b/flutter_inappwebview_windows/lib/src/in_app_webview/in_app_webview.dart index 0b2c515d5..ff93cc9c6 100644 --- a/flutter_inappwebview_windows/lib/src/in_app_webview/in_app_webview.dart +++ b/flutter_inappwebview_windows/lib/src/in_app_webview/in_app_webview.dart @@ -37,8 +37,10 @@ class WindowsInAppWebViewWidgetCreationParams super.shouldOverrideUrlLoading, super.onLoadResource, super.onScrollChanged, - @Deprecated('Use onDownloadStartRequest instead') super.onDownloadStart, + @Deprecated('Use onDownloadStarting instead') super.onDownloadStart, + @Deprecated('Use onDownloadStarting instead') super.onDownloadStartRequest, + super.onDownloadStarting, @Deprecated('Use onLoadResourceWithCustomScheme instead') super.onLoadResourceCustomScheme, super.onLoadResourceWithCustomScheme, @@ -163,6 +165,7 @@ class WindowsInAppWebViewWidgetCreationParams onScrollChanged: params.onScrollChanged, onDownloadStart: params.onDownloadStart, onDownloadStartRequest: params.onDownloadStartRequest, + onDownloadStarting: params.onDownloadStarting, onLoadResourceCustomScheme: params.onLoadResourceCustomScheme, onLoadResourceWithCustomScheme: params.onLoadResourceWithCustomScheme, @@ -282,6 +285,13 @@ class WindowsInAppWebViewWidget extends PlatformInAppWebViewWidget { WindowsHeadlessInAppWebView? get _windowsHeadlessInAppWebView => params.headlessWebView as WindowsHeadlessInAppWebView?; + static final WindowsInAppWebViewWidget _staticValue = + WindowsInAppWebViewWidget(WindowsInAppWebViewWidgetCreationParams()); + + factory WindowsInAppWebViewWidget.static() { + return _staticValue; + } + @override Widget build(BuildContext context) { final initialSettings = params.initialSettings ?? InAppWebViewSettings(); @@ -360,15 +370,24 @@ class WindowsInAppWebViewWidget extends PlatformInAppWebViewWidget { if (params.onLoadResource != null && settings.useOnLoadResource == null) { settings.useOnLoadResource = true; } - if (params.onDownloadStartRequest != null && + if ((params.onDownloadStartRequest != null || + params.onDownloadStarting != null) && settings.useOnDownloadStart == null) { settings.useOnDownloadStart = true; } if ((params.shouldInterceptAjaxRequest != null || - params.onAjaxProgress != null || - params.onAjaxReadyStateChange != null) && - settings.useShouldInterceptAjaxRequest == null) { - settings.useShouldInterceptAjaxRequest = true; + params.onAjaxProgress != null || + params.onAjaxReadyStateChange != null)) { + if (settings.useShouldInterceptAjaxRequest == null) { + settings.useShouldInterceptAjaxRequest = true; + } + if (params.onAjaxReadyStateChange != null && + settings.useOnAjaxReadyStateChange == null) { + settings.useOnAjaxReadyStateChange = true; + } + if (params.onAjaxProgress != null && settings.useOnAjaxProgress == null) { + settings.useOnAjaxProgress = true; + } } if (params.shouldInterceptFetchRequest != null && settings.useShouldInterceptFetchRequest == null) { diff --git a/flutter_inappwebview_windows/lib/src/in_app_webview/in_app_webview_controller.dart b/flutter_inappwebview_windows/lib/src/in_app_webview/in_app_webview_controller.dart index 8f1ab3ffd..ce4b9d7ee 100644 --- a/flutter_inappwebview_windows/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/flutter_inappwebview_windows/lib/src/in_app_webview/in_app_webview_controller.dart @@ -1,39 +1,18 @@ -import 'dart:io'; import 'dart:collection'; import 'dart:convert'; import 'dart:core'; import 'dart:developer' as developer; -import 'dart:typed_data'; -import 'dart:ui'; +import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import '../web_message/main.dart'; - import '../in_app_browser/in_app_browser.dart'; +import '../print_job/main.dart'; import '../web_storage/web_storage.dart'; - -import 'headless_in_app_webview.dart'; import '_static_channel.dart'; - -import '../print_job/main.dart'; - -///List of forbidden names for JavaScript handlers. -// ignore: non_constant_identifier_names -final _JAVASCRIPT_HANDLER_FORBIDDEN_NAMES = UnmodifiableListView([ - "onLoadResource", - "shouldInterceptAjaxRequest", - "onAjaxReadyStateChange", - "onAjaxProgress", - "shouldInterceptFetchRequest", - "onPrintRequest", - "onWindowFocus", - "onWindowBlur", - "callAsyncJavaScript", - "evaluateJavaScriptWithContentWorld" -]); +import 'headless_in_app_webview.dart'; /// Object specifying creation parameters for creating a [WindowsInAppWebViewController]. /// @@ -66,16 +45,13 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController static final MethodChannel _staticChannel = IN_APP_WEBVIEW_STATIC_CHANNEL; // List of properties to be saved and restored for keep alive feature - Map _javaScriptHandlersMap = - HashMap(); + Map _javaScriptHandlersMap = HashMap(); Map> _userScripts = { UserScriptInjectionTime.AT_DOCUMENT_START: [], UserScriptInjectionTime.AT_DOCUMENT_END: [] }; Set _webMessageListenerObjNames = Set(); Map _injectedScriptsFromURL = {}; - Set _webMessageChannels = Set(); - Set _webMessageListeners = Set(); Map _devToolsProtocolEventListenerMap = HashMap(); @@ -183,8 +159,6 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController javaScriptHandlersMap: _javaScriptHandlersMap, userScripts: _userScripts, webMessageListenerObjNames: _webMessageListenerObjNames, - webMessageChannels: _webMessageChannels, - webMessageListeners: _webMessageListeners, devToolsProtocolEventListenerMap: _devToolsProtocolEventListenerMap); } else { @@ -193,10 +167,6 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController _javaScriptHandlersMap = props.javaScriptHandlersMap; _userScripts = props.userScripts; _webMessageListenerObjNames = props.webMessageListenerObjNames; - _webMessageChannels = - props.webMessageChannels as Set; - _webMessageListeners = - props.webMessageListeners as Set; _devToolsProtocolEventListenerMap = props.devToolsProtocolEventListenerMap; } @@ -369,11 +339,11 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController _inAppBrowserEventHandler!.onScrollChanged(x, y); } break; - case "onDownloadStartRequest": + case "onDownloadStarting": if ((webviewParams != null && - // ignore: deprecated_member_use_from_same_package (webviewParams!.onDownloadStart != null || - webviewParams!.onDownloadStartRequest != null)) || + webviewParams!.onDownloadStartRequest != null || + webviewParams!.onDownloadStarting != null)) || _inAppBrowserEventHandler != null) { Map arguments = call.arguments.cast(); @@ -381,20 +351,25 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController DownloadStartRequest.fromMap(arguments)!; if (webviewParams != null) { - if (webviewParams!.onDownloadStartRequest != null) + if (webviewParams!.onDownloadStarting != null) + return (await webviewParams!.onDownloadStarting!( + _controllerFromPlatform, downloadStartRequest)) + ?.toMap(); + else if (webviewParams!.onDownloadStartRequest != null) webviewParams!.onDownloadStartRequest!( _controllerFromPlatform, downloadStartRequest); else { - // ignore: deprecated_member_use_from_same_package webviewParams!.onDownloadStart!( _controllerFromPlatform, downloadStartRequest.url); } } else { - // ignore: deprecated_member_use_from_same_package _inAppBrowserEventHandler! .onDownloadStart(downloadStartRequest.url); _inAppBrowserEventHandler! .onDownloadStartRequest(downloadStartRequest); + return (await _inAppBrowserEventHandler! + .onDownloadStarting(downloadStartRequest)) + ?.toMap(); } } break; @@ -910,6 +885,16 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController _inAppBrowserEventHandler != null) { Map arguments = call.arguments.cast(); + + if (arguments['protectionSpace'] is Map && + arguments['protectionSpace']['sslCertificate'] is Map && + arguments['protectionSpace']['sslCertificate']['x509Certificate'] + is String) { + arguments['protectionSpace']['sslCertificate']['x509Certificate'] = + utf8.encode(arguments['protectionSpace']['sslCertificate'] + ['x509Certificate']); + } + HttpAuthenticationChallenge challenge = HttpAuthenticationChallenge.fromMap(arguments)!; @@ -930,6 +915,16 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController _inAppBrowserEventHandler != null) { Map arguments = call.arguments.cast(); + + if (arguments['protectionSpace'] is Map && + arguments['protectionSpace']['sslCertificate'] is Map && + arguments['protectionSpace']['sslCertificate']['x509Certificate'] + is String) { + arguments['protectionSpace']['sslCertificate']['x509Certificate'] = + utf8.encode(arguments['protectionSpace']['sslCertificate'] + ['x509Certificate']); + } + ServerTrustChallenge challenge = ServerTrustChallenge.fromMap(arguments)!; @@ -950,6 +945,24 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController _inAppBrowserEventHandler != null) { Map arguments = call.arguments.cast(); + + if (arguments['protectionSpace'] is Map && + arguments['protectionSpace']['sslCertificate'] is Map && + arguments['protectionSpace']['sslCertificate']['x509Certificate'] + is String) { + arguments['protectionSpace']['sslCertificate']['x509Certificate'] = + utf8.encode(arguments['protectionSpace']['sslCertificate'] + ['x509Certificate']); + } + + arguments['mutuallyTrustedCertificates'] = + (arguments['mutuallyTrustedCertificates'] as List) + .cast>() + .map((c) { + c['x509Certificate'] = utf8.encode(c['x509Certificate']); + return c; + }).toList(); + ClientCertChallenge challenge = ClientCertChallenge.fromMap(arguments)!; @@ -1422,19 +1435,53 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController this._devToolsProtocolEventListenerMap[eventName]!.call(data); } break; + case "onProcessFailed": + if ((webviewParams != null && webviewParams!.onProcessFailed != null) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + final detail = ProcessFailedDetail.fromMap(arguments)!; + + if (webviewParams != null && webviewParams!.onProcessFailed != null) + webviewParams!.onProcessFailed!(_controllerFromPlatform, detail); + else + _inAppBrowserEventHandler!.onProcessFailed(detail); + } + break; + case "onAcceleratorKeyPressed": + if ((webviewParams != null && + webviewParams!.onAcceleratorKeyPressed != null) || + _inAppBrowserEventHandler != null) { + Map arguments = + call.arguments.cast(); + final detail = AcceleratorKeyPressedDetail.fromMap(arguments)!; + + if (webviewParams != null && + webviewParams!.onAcceleratorKeyPressed != null) + webviewParams!.onAcceleratorKeyPressed!( + _controllerFromPlatform, detail); + else + _inAppBrowserEventHandler!.onAcceleratorKeyPressed(detail); + } + break; case "onCallJsHandler": String handlerName = call.arguments["handlerName"]; + Map handlerDataMap = + call.arguments["data"].cast(); // decode args to json - List args = jsonDecode(call.arguments["args"]); + handlerDataMap["args"] = jsonDecode(handlerDataMap["args"]); + final handlerData = + JavaScriptHandlerFunctionData.fromMap(handlerDataMap)!; - _debugLog(handlerName, args); + _debugLog(handlerName, handlerData); switch (handlerName) { case "onLoadResource": if ((webviewParams != null && webviewParams!.onLoadResource != null) || _inAppBrowserEventHandler != null) { - Map arguments = args[0].cast(); + Map arguments = + handlerData.args[0].cast(); arguments["startTime"] = arguments["startTime"] is int ? arguments["startTime"].toDouble() : arguments["startTime"]; @@ -1456,7 +1503,8 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController if ((webviewParams != null && webviewParams!.shouldInterceptAjaxRequest != null) || _inAppBrowserEventHandler != null) { - Map arguments = args[0].cast(); + Map arguments = + handlerData.args[0].cast(); AjaxRequest request = AjaxRequest.fromMap(arguments)!; if (webviewParams != null && @@ -1473,43 +1521,46 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController if ((webviewParams != null && webviewParams!.onAjaxReadyStateChange != null) || _inAppBrowserEventHandler != null) { - Map arguments = args[0].cast(); + Map arguments = + handlerData.args[0].cast(); AjaxRequest request = AjaxRequest.fromMap(arguments)!; if (webviewParams != null && webviewParams!.onAjaxReadyStateChange != null) - return (await webviewParams!.onAjaxReadyStateChange!( + return jsonEncode((await webviewParams!.onAjaxReadyStateChange!( _controllerFromPlatform, request)) - ?.toNativeValue(); + ?.toNativeValue()); else - return (await _inAppBrowserEventHandler! + return jsonEncode((await _inAppBrowserEventHandler! .onAjaxReadyStateChange(request)) - ?.toNativeValue(); + ?.toNativeValue()); } return null; case "onAjaxProgress": if ((webviewParams != null && webviewParams!.onAjaxProgress != null) || _inAppBrowserEventHandler != null) { - Map arguments = args[0].cast(); + Map arguments = + handlerData.args[0].cast(); AjaxRequest request = AjaxRequest.fromMap(arguments)!; if (webviewParams != null && webviewParams!.onAjaxProgress != null) - return (await webviewParams!.onAjaxProgress!( + return jsonEncode((await webviewParams!.onAjaxProgress!( _controllerFromPlatform, request)) - ?.toNativeValue(); + ?.toNativeValue()); else - return (await _inAppBrowserEventHandler! - .onAjaxProgress(request)) - ?.toNativeValue(); + return jsonEncode( + (await _inAppBrowserEventHandler!.onAjaxProgress(request)) + ?.toNativeValue()); } return null; case "shouldInterceptFetchRequest": if ((webviewParams != null && webviewParams!.shouldInterceptFetchRequest != null) || _inAppBrowserEventHandler != null) { - Map arguments = args[0].cast(); + Map arguments = + handlerData.args[0].cast(); FetchRequest request = FetchRequest.fromMap(arguments)!; if (webviewParams != null && @@ -1535,7 +1586,7 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController _inAppBrowserEventHandler!.onWindowBlur(); return null; case "onInjectedScriptLoaded": - String id = args[0]; + String id = handlerData.args[0]; var onLoadCallback = _injectedScriptsFromURL[id]?.onLoad; if ((webviewParams != null || _inAppBrowserEventHandler != null) && onLoadCallback != null) { @@ -1543,7 +1594,7 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController } return null; case "onInjectedScriptError": - String id = args[0]; + String id = handlerData.args[0]; var onErrorCallback = _injectedScriptsFromURL[id]?.onError; if ((webviewParams != null || _inAppBrowserEventHandler != null) && onErrorCallback != null) { @@ -1555,7 +1606,19 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController if (_javaScriptHandlersMap.containsKey(handlerName)) { // convert result to json try { - return jsonEncode(await _javaScriptHandlersMap[handlerName]!(args)); + var jsHandlerResult = null; + if (_javaScriptHandlersMap[handlerName] + is JavaScriptHandlerCallback) { + jsHandlerResult = await (_javaScriptHandlersMap[handlerName] + as JavaScriptHandlerCallback)(handlerData.args); + } else if (_javaScriptHandlersMap[handlerName] + is JavaScriptHandlerFunction) { + jsHandlerResult = await (_javaScriptHandlersMap[handlerName] + as JavaScriptHandlerFunction)(handlerData); + } else { + jsHandlerResult = await _javaScriptHandlersMap[handlerName]!(); + } + return jsonEncode(jsHandlerResult); } catch (error, stacktrace) { developer.log(error.toString() + '\n' + stacktrace.toString(), name: 'JavaScript Handler "$handlerName"'); @@ -2002,16 +2065,14 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController @override void addJavaScriptHandler( - {required String handlerName, - required JavaScriptHandlerCallback callback}) { - assert(!_JAVASCRIPT_HANDLER_FORBIDDEN_NAMES.contains(handlerName), + {required String handlerName, required Function callback}) { + assert(!kJavaScriptHandlerForbiddenNames.contains(handlerName), '"$handlerName" is a forbidden name!'); this._javaScriptHandlersMap[handlerName] = (callback); } @override - JavaScriptHandlerCallback? removeJavaScriptHandler( - {required String handlerName}) { + Function? removeJavaScriptHandler({required String handlerName}) { return this._javaScriptHandlersMap.remove(handlerName); } @@ -2484,55 +2545,6 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController return await channel?.invokeMethod('isSecureContext', args) ?? false; } - @override - Future createWebMessageChannel() async { - Map args = {}; - Map? result = - (await channel?.invokeMethod('createWebMessageChannel', args)) - ?.cast(); - final webMessageChannel = WindowsWebMessageChannel.static().fromMap(result); - if (webMessageChannel != null) { - _webMessageChannels.add(webMessageChannel); - } - return webMessageChannel; - } - - @override - Future postWebMessage( - {required WebMessage message, WebUri? targetOrigin}) async { - if (targetOrigin == null) { - targetOrigin = WebUri(''); - } - Map args = {}; - args.putIfAbsent('message', () => message.toMap()); - args.putIfAbsent('targetOrigin', () => targetOrigin.toString()); - await channel?.invokeMethod('postWebMessage', args); - } - - @override - Future addWebMessageListener( - PlatformWebMessageListener webMessageListener) async { - assert(!_webMessageListeners.contains(webMessageListener), - "${webMessageListener} was already added."); - assert( - !_webMessageListenerObjNames - .contains(webMessageListener.params.jsObjectName), - "jsObjectName ${webMessageListener.params.jsObjectName} was already added."); - _webMessageListeners.add(webMessageListener as WindowsWebMessageListener); - _webMessageListenerObjNames.add(webMessageListener.params.jsObjectName); - - Map args = {}; - args.putIfAbsent('webMessageListener', () => webMessageListener.toMap()); - await channel?.invokeMethod('addWebMessageListener', args); - } - - @override - bool hasWebMessageListener(PlatformWebMessageListener webMessageListener) { - return _webMessageListeners.contains(webMessageListener) || - _webMessageListenerObjNames - .contains(webMessageListener.params.jsObjectName); - } - @override Future canScrollVertically() async { Map args = {}; @@ -2691,6 +2703,12 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController this._devToolsProtocolEventListenerMap.remove(eventName); } + @override + Future clearSslPreferences() async { + Map args = {}; + await channel?.invokeMethod('clearSslPreferences', args); + } + @override Future pause() async { Map args = {}; @@ -2703,6 +2721,14 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController await channel?.invokeMethod('resume', args); } + @override + Future isInterfaceSupported(WebViewInterface interface) async { + Map args = {}; + args.putIfAbsent('interface', () => interface.toNativeValue()); + return await channel?.invokeMethod('isInterfaceSupported', args) ?? + false; + } + @override Future getDefaultUserAgent() async { Map args = {}; @@ -2733,6 +2759,23 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController await _staticChannel.invokeMethod('clearAllCache', args); } + @override + Future setJavaScriptBridgeName(String bridgeName) async { + assert(RegExp(r'^[a-zA-Z_]\w*$').hasMatch(bridgeName), + 'bridgeName must be a non-empty string with only alphanumeric and underscore characters. It can\'t start with a number.'); + Map args = {}; + args.putIfAbsent('bridgeName', () => bridgeName); + await _staticChannel.invokeMethod('setJavaScriptBridgeName', args); + } + + @override + Future getJavaScriptBridgeName() async { + Map args = {}; + return await _staticChannel.invokeMethod( + 'getJavaScriptBridgeName', args) ?? + ''; + } + @override Future get tRexRunnerHtml async => await rootBundle.loadString( 'packages/flutter_inappwebview/assets/t_rex_runner/t-rex.html'); @@ -2757,14 +2800,6 @@ class WindowsInAppWebViewController extends PlatformInAppWebViewController _userScripts.clear(); _webMessageListenerObjNames.clear(); _injectedScriptsFromURL.clear(); - for (final webMessageChannel in _webMessageChannels) { - webMessageChannel.dispose(); - } - _webMessageChannels.clear(); - for (final webMessageListener in _webMessageListeners) { - webMessageListener.dispose(); - } - _webMessageListeners.clear(); _devToolsProtocolEventListenerMap.clear(); } } diff --git a/flutter_inappwebview_windows/lib/src/inappwebview_platform.dart b/flutter_inappwebview_windows/lib/src/inappwebview_platform.dart index b3ac05646..877576a02 100644 --- a/flutter_inappwebview_windows/lib/src/inappwebview_platform.dart +++ b/flutter_inappwebview_windows/lib/src/inappwebview_platform.dart @@ -2,11 +2,11 @@ import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_pla import 'cookie_manager.dart'; import 'in_app_browser/in_app_browser.dart'; +import 'in_app_webview/headless_in_app_webview.dart'; import 'in_app_webview/in_app_webview.dart'; import 'in_app_webview/in_app_webview_controller.dart'; -import 'in_app_webview/headless_in_app_webview.dart'; -import 'webview_environment/webview_environment.dart'; import 'web_storage/web_storage.dart'; +import 'webview_environment/webview_environment.dart'; /// Implementation of [InAppWebViewPlatform] using the WebKit API. class WindowsInAppWebViewPlatform extends InAppWebViewPlatform { @@ -26,6 +26,15 @@ class WindowsInAppWebViewPlatform extends InAppWebViewPlatform { return WindowsCookieManager(params); } + /// Creates a new empty [WindowsCookieManager] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [CookieManager] in `flutter_inappwebview` instead. + @override + WindowsCookieManager createPlatformCookieManagerStatic() { + return WindowsCookieManager.static(); + } + /// Creates a new [WindowsInAppWebViewController]. /// /// This function should only be called by the app-facing package. @@ -57,6 +66,15 @@ class WindowsInAppWebViewPlatform extends InAppWebViewPlatform { return WindowsInAppWebViewWidget(params); } + /// Creates a new empty [WindowsInAppWebViewWidget] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [InAppWebView] in `flutter_inappwebview` instead. + @override + WindowsInAppWebViewWidget createPlatformInAppWebViewWidgetStatic() { + return WindowsInAppWebViewWidget.static(); + } + /// Creates a new [WindowsInAppBrowser]. /// /// This function should only be called by the app-facing package. @@ -88,6 +106,15 @@ class WindowsInAppWebViewPlatform extends InAppWebViewPlatform { return WindowsHeadlessInAppWebView(params); } + /// Creates a new empty [WindowsHeadlessInAppWebView] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [HeadlessInAppWebView] in `flutter_inappwebview` instead. + @override + WindowsHeadlessInAppWebView createPlatformHeadlessInAppWebViewStatic() { + return WindowsHeadlessInAppWebView.static(); + } + /// Creates a new [WindowsWebViewEnvironment]. /// /// This function should only be called by the app-facing package. @@ -119,6 +146,17 @@ class WindowsInAppWebViewPlatform extends InAppWebViewPlatform { return WindowsWebStorage(params); } + /// Creates a new empty [WindowsWebStorage] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [WebStorage] in `flutter_inappwebview` instead. + @override + WindowsWebStorage createPlatformWebStorageStatic() { + return WindowsWebStorage(WindowsWebStorageCreationParams( + localStorage: createPlatformLocalStorageStatic(), + sessionStorage: createPlatformSessionStorageStatic())); + } + /// Creates a new [WindowsLocalStorage]. /// /// This function should only be called by the app-facing package. @@ -130,6 +168,15 @@ class WindowsInAppWebViewPlatform extends InAppWebViewPlatform { return WindowsLocalStorage(params); } + /// Creates a new empty [WindowsLocalStorage] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [LocalStorage] in `flutter_inappwebview` instead. + @override + WindowsLocalStorage createPlatformLocalStorageStatic() { + return WindowsLocalStorage.defaultStorage(controller: null); + } + /// Creates a new [WindowsSessionStorage]. /// /// This function should only be called by the app-facing package. @@ -140,4 +187,326 @@ class WindowsInAppWebViewPlatform extends InAppWebViewPlatform { ) { return WindowsSessionStorage(params); } + + /// Creates a new empty [WindowsSessionStorage] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [SessionStorage] in `flutter_inappwebview` instead. + @override + WindowsSessionStorage createPlatformSessionStorageStatic() { + return WindowsSessionStorage.defaultStorage(controller: null); + } + + /// Creates a new empty [PlatformWebStorageManager] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [WebStorageManager] in `flutter_inappwebview` instead. + @override + PlatformWebStorageManager createPlatformWebStorageManagerStatic() { + return _PlatformWebStorageManager.static(); + } + + // ************************************************************************ // + // Create static instances of unsupported classes to be able to call // + // isClassSupported, isMethodSupported, isPropertySupported, etc. // + // static methods without throwing a missing platform implementation // + // exception. // + // ************************************************************************ // + + /// Creates a new empty [PlatformChromeSafariBrowser] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [ChromeSafariBrowser] in `flutter_inappwebview` instead. + PlatformChromeSafariBrowser createPlatformChromeSafariBrowserStatic() { + return _PlatformChromeSafariBrowser.static(); + } + + /// Creates a new empty [PlatformHttpAuthCredentialDatabase] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [HttpAuthCredentialDatabase] in `flutter_inappwebview` instead. + @override + PlatformHttpAuthCredentialDatabase + createPlatformHttpAuthCredentialDatabaseStatic() { + return _PlatformHttpAuthCredentialDatabase.static(); + } + + /// Creates a new empty [PlatformProcessGlobalConfig] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [ProcessGlobalConfig] in `flutter_inappwebview` instead. + @override + PlatformProcessGlobalConfig createPlatformProcessGlobalConfigStatic() { + return _PlatformProcessGlobalConfig.static(); + } + + /// Creates a new empty [PlatformProxyController] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [ProxyController] in `flutter_inappwebview` instead. + @override + PlatformProxyController createPlatformProxyControllerStatic() { + return _PlatformProxyController.static(); + } + + /// Creates a new empty [PlatformServiceWorkerController] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [ServiceWorkerController] in `flutter_inappwebview` instead. + @override + PlatformServiceWorkerController + createPlatformServiceWorkerControllerStatic() { + return _PlatformServiceWorkerController.static(); + } + + /// Creates a new empty [PlatformTracingController] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [TracingController] in `flutter_inappwebview` instead. + @override + PlatformTracingController createPlatformTracingControllerStatic() { + return _PlatformTracingController.static(); + } + + /// Creates a new empty [PlatformFindInteractionController] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [FindInteractionController] in `flutter_inappwebview` instead. + @override + PlatformFindInteractionController + createPlatformFindInteractionControllerStatic() { + return _PlatformFindInteractionController.static(); + } + + /// Creates a new empty [PlatformPrintJobController] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [PrintJobController] in `flutter_inappwebview` instead. + @override + PlatformPrintJobController createPlatformPrintJobControllerStatic() { + return _PlatformPrintJobController.static(); + } + + /// Creates a new empty [PlatformPullToRefreshController] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [PullToRefreshController] in `flutter_inappwebview` instead. + @override + PlatformPullToRefreshController + createPlatformPullToRefreshControllerStatic() { + return _PlatformPullToRefreshController.static(); + } + + /// Creates a new empty [PlatformWebAuthenticationSession] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [WebAuthenticationSession] in `flutter_inappwebview` instead. + @override + PlatformWebAuthenticationSession + createPlatformWebAuthenticationSessionStatic() { + return _PlatformWebAuthenticationSession.static(); + } + + /// Creates a new empty [PlatformWebMessageChannel] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [WebMessageChannel] in `flutter_inappwebview` instead. + @override + PlatformWebMessageChannel createPlatformWebMessageChannelStatic() { + return _PlatformWebMessageChannel.static(); + } + + /// Creates a new empty [PlatformWebMessageListener] to access static methods. + /// + /// This function should only be called by the app-facing package. + /// Look at using [WebMessageListener] in `flutter_inappwebview` instead. + @override + PlatformWebMessageListener createPlatformWebMessageListenerStatic() { + return _PlatformWebMessageListener.static(); + } +} + +class _PlatformChromeSafariBrowser extends PlatformChromeSafariBrowser { + _PlatformChromeSafariBrowser(PlatformChromeSafariBrowserCreationParams params) + : super.implementation(params); + static final _PlatformChromeSafariBrowser _staticValue = + _PlatformChromeSafariBrowser( + const PlatformChromeSafariBrowserCreationParams()); + + factory _PlatformChromeSafariBrowser.static() => _staticValue; +} + +class _PlatformHttpAuthCredentialDatabase + extends PlatformHttpAuthCredentialDatabase { + _PlatformHttpAuthCredentialDatabase( + PlatformHttpAuthCredentialDatabaseCreationParams params) + : super.implementation(params); + static final _PlatformHttpAuthCredentialDatabase _staticValue = + _PlatformHttpAuthCredentialDatabase( + const PlatformHttpAuthCredentialDatabaseCreationParams()); + + factory _PlatformHttpAuthCredentialDatabase.static() => _staticValue; +} + +class _PlatformProcessGlobalConfig extends PlatformProcessGlobalConfig { + _PlatformProcessGlobalConfig(PlatformProcessGlobalConfigCreationParams params) + : super.implementation(params); + static final _PlatformProcessGlobalConfig _staticValue = + _PlatformProcessGlobalConfig( + const PlatformProcessGlobalConfigCreationParams()); + + factory _PlatformProcessGlobalConfig.static() => _staticValue; +} + +class _PlatformProxyController extends PlatformProxyController { + _PlatformProxyController(PlatformProxyControllerCreationParams params) + : super.implementation(params); + static final _PlatformProxyController _staticValue = + _PlatformProxyController(const PlatformProxyControllerCreationParams()); + + factory _PlatformProxyController.static() => _staticValue; +} + +class _PlatformServiceWorkerController extends PlatformServiceWorkerController { + _PlatformServiceWorkerController( + PlatformServiceWorkerControllerCreationParams params) + : super.implementation(params); + static final _PlatformServiceWorkerController _staticValue = + _PlatformServiceWorkerController( + const PlatformServiceWorkerControllerCreationParams()); + + factory _PlatformServiceWorkerController.static() => _staticValue; + + @override + ServiceWorkerClient? get serviceWorkerClient => throw UnimplementedError(); +} + +class _PlatformTracingController extends PlatformTracingController { + _PlatformTracingController(PlatformTracingControllerCreationParams params) + : super.implementation(params); + static final _PlatformTracingController _staticValue = + _PlatformTracingController( + const PlatformTracingControllerCreationParams()); + + factory _PlatformTracingController.static() => _staticValue; +} + +class _PlatformFindInteractionController + extends PlatformFindInteractionController { + _PlatformFindInteractionController( + PlatformFindInteractionControllerCreationParams params) + : super.implementation(params); + static final _PlatformFindInteractionController _staticValue = + _PlatformFindInteractionController( + const PlatformFindInteractionControllerCreationParams()); + + factory _PlatformFindInteractionController.static() => _staticValue; +} + +class _PlatformPrintJobController extends PlatformPrintJobController { + _PlatformPrintJobController(PlatformPrintJobControllerCreationParams params) + : super.implementation(params); + + static final _PlatformPrintJobController _staticValue = + _PlatformPrintJobController( + const PlatformPrintJobControllerCreationParams(id: '')); + + factory _PlatformPrintJobController.static() => _staticValue; +} + +class _PlatformPullToRefreshController extends PlatformPullToRefreshController { + _PlatformPullToRefreshController( + PlatformPullToRefreshControllerCreationParams params) + : super.implementation(params); + + static final _PlatformPullToRefreshController _staticValue = + _PlatformPullToRefreshController( + PlatformPullToRefreshControllerCreationParams()); + + factory _PlatformPullToRefreshController.static() => _staticValue; +} + +class _PlatformWebAuthenticationSession + extends PlatformWebAuthenticationSession { + _PlatformWebAuthenticationSession( + PlatformWebAuthenticationSessionCreationParams params) + : super.implementation(params); + + static final _PlatformWebAuthenticationSession _staticValue = + _PlatformWebAuthenticationSession( + const PlatformWebAuthenticationSessionCreationParams()); + + factory _PlatformWebAuthenticationSession.static() => _staticValue; +} + +class _PlatformWebMessageChannel extends PlatformWebMessageChannel { + _PlatformWebMessageChannel(PlatformWebMessageChannelCreationParams params) + : super.implementation(params); + + static final _PlatformWebMessageChannel _staticValue = + _PlatformWebMessageChannel(PlatformWebMessageChannelCreationParams( + id: '', + port1: _PlatformWebMessagePort( + const PlatformWebMessagePortCreationParams(index: 0)), + port2: _PlatformWebMessagePort( + const PlatformWebMessagePortCreationParams(index: 1)))); + + factory _PlatformWebMessageChannel.static() => _staticValue; +} + +class _PlatformWebMessageListener extends PlatformWebMessageListener { + _PlatformWebMessageListener(PlatformWebMessageListenerCreationParams params) + : super.implementation(params); + + static final _PlatformWebMessageListener _staticValue = + _PlatformWebMessageListener( + const PlatformWebMessageListenerCreationParams(jsObjectName: '')); + + factory _PlatformWebMessageListener.static() => _staticValue; +} + +class _PlatformWebMessagePort extends PlatformWebMessagePort { + _PlatformWebMessagePort(PlatformWebMessagePortCreationParams params) + : super.implementation(params); + + static final _PlatformWebMessagePort _staticValue = _PlatformWebMessagePort( + const PlatformWebMessagePortCreationParams(index: 0)); + + factory _PlatformWebMessagePort.static() => _staticValue; + + @override + Future close() { + throw UnimplementedError(); + } + + @override + Future postMessage(WebMessage message) { + throw UnimplementedError(); + } + + @override + Future setWebMessageCallback(WebMessageCallback? onMessage) { + throw UnimplementedError(); + } + + @override + Map toJson() { + throw UnimplementedError(); + } + + @override + Map toMap({EnumMethod? enumMethod}) { + throw UnimplementedError(); + } +} + +class _PlatformWebStorageManager extends PlatformWebStorageManager { + _PlatformWebStorageManager(PlatformWebStorageManagerCreationParams params) + : super.implementation(params); + + static final _PlatformWebStorageManager _staticValue = + _PlatformWebStorageManager( + const PlatformWebStorageManagerCreationParams()); + + factory _PlatformWebStorageManager.static() => _staticValue; } diff --git a/flutter_inappwebview_windows/lib/src/main.dart b/flutter_inappwebview_windows/lib/src/main.dart index 4fce8f8c0..e93d1dee6 100644 --- a/flutter_inappwebview_windows/lib/src/main.dart +++ b/flutter_inappwebview_windows/lib/src/main.dart @@ -5,7 +5,6 @@ export 'web_storage/main.dart'; export 'cookie_manager.dart' hide InternalCookieManager; export 'http_auth_credentials_database.dart' hide InternalHttpAuthCredentialDatabase; -export 'web_message/main.dart'; export 'print_job/main.dart'; export 'find_interaction/main.dart'; export 'webview_environment/main.dart'; diff --git a/flutter_inappwebview_windows/lib/src/platform_util.dart b/flutter_inappwebview_windows/lib/src/platform_util.dart index 27e96478b..3f3b7c8fa 100644 --- a/flutter_inappwebview_windows/lib/src/platform_util.dart +++ b/flutter_inappwebview_windows/lib/src/platform_util.dart @@ -1,11 +1,21 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; +abstract mixin class PlatformUtilListener { + void onWindowMove() {} + void onWindowStartMove() {} + void onWindowEndMove() {} +} + ///Platform native utilities class PlatformUtil { static PlatformUtil? _instance; static const MethodChannel _channel = MethodChannel('com.pichillilorenzo/flutter_inappwebview_platformutil'); + static final ObserverList _listeners = + ObserverList(); + PlatformUtil._(); ///Get [PlatformUtil] instance. @@ -26,39 +36,32 @@ class PlatformUtil { return _instance!; } - static Future _handleMethod(MethodCall call) async {} - - String? _cachedSystemVersion; - - ///Get current platform system version. - Future getSystemVersion() async { - if (_cachedSystemVersion != null) { - return _cachedSystemVersion!; + static Future _handleMethod(MethodCall call) async { + if (call.method == 'onEvent') { + String eventName = call.arguments['eventName']; + for (final listener in _listeners) { + switch (eventName) { + case 'onWindowMove': + listener.onWindowMove(); + break; + case 'onWindowStartMove': + listener.onWindowStartMove(); + break; + case 'onWindowEndMove': + listener.onWindowEndMove(); + break; + } + } } - Map args = {}; - _cachedSystemVersion = - await _channel.invokeMethod('getSystemVersion', args); - return _cachedSystemVersion!; } - ///Format date. - Future formatDate( - {required DateTime date, - required String format, - String locale = "en_US", - String timezone = "UTC"}) async { - Map args = {}; - args.putIfAbsent('date', () => date.millisecondsSinceEpoch); - args.putIfAbsent('format', () => format); - args.putIfAbsent('locale', () => locale); - args.putIfAbsent('timezone', () => timezone); - return await _channel.invokeMethod('formatDate', args); + /// Add a listener to the window. + void addListener(PlatformUtilListener listener) { + _listeners.add(listener); } - ///Get cookie expiration date used by Web platform. - Future getWebCookieExpirationDate({required DateTime date}) async { - Map args = {}; - args.putIfAbsent('date', () => date.millisecondsSinceEpoch); - return await _channel.invokeMethod('getWebCookieExpirationDate', args); + /// Remove a listener from the window. + void removeListener(PlatformUtilListener listener) { + _listeners.remove(listener); } } diff --git a/flutter_inappwebview_windows/lib/src/print_job/print_job_controller.dart b/flutter_inappwebview_windows/lib/src/print_job/print_job_controller.dart index a1da365a4..b2b6e430e 100644 --- a/flutter_inappwebview_windows/lib/src/print_job/print_job_controller.dart +++ b/flutter_inappwebview_windows/lib/src/print_job/print_job_controller.dart @@ -11,16 +11,14 @@ import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_pla class WindowsPrintJobControllerCreationParams extends PlatformPrintJobControllerCreationParams { /// Creates a new [WindowsPrintJobControllerCreationParams] instance. - const WindowsPrintJobControllerCreationParams( - {required super.id, super.onComplete}); + const WindowsPrintJobControllerCreationParams({required super.id}); /// Creates a [WindowsPrintJobControllerCreationParams] instance based on [PlatformPrintJobControllerCreationParams]. factory WindowsPrintJobControllerCreationParams.fromPlatformPrintJobControllerCreationParams( // Recommended placeholder to prevent being broken by platform interface. // ignore: avoid_unused_constructor_parameters PlatformPrintJobControllerCreationParams params) { - return WindowsPrintJobControllerCreationParams( - id: params.id, onComplete: params.onComplete); + return WindowsPrintJobControllerCreationParams(id: params.id); } } @@ -35,7 +33,6 @@ class WindowsPrintJobController extends PlatformPrintJobController : WindowsPrintJobControllerCreationParams .fromPlatformPrintJobControllerCreationParams(params), ) { - onComplete = params.onComplete; channel = MethodChannel( 'com.pichillilorenzo/flutter_inappwebview_printjobcontroller_${params.id}'); handler = _handleMethod; diff --git a/flutter_inappwebview_windows/lib/src/web_message/main.dart b/flutter_inappwebview_windows/lib/src/web_message/main.dart deleted file mode 100644 index d41e30c75..000000000 --- a/flutter_inappwebview_windows/lib/src/web_message/main.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'web_message_port.dart' hide InternalWebMessagePort; -export 'web_message_channel.dart' hide InternalWebMessageChannel; -export 'web_message_listener.dart'; diff --git a/flutter_inappwebview_windows/lib/src/web_message/web_message_channel.dart b/flutter_inappwebview_windows/lib/src/web_message/web_message_channel.dart deleted file mode 100644 index 19c99b315..000000000 --- a/flutter_inappwebview_windows/lib/src/web_message/web_message_channel.dart +++ /dev/null @@ -1,120 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; -import 'web_message_port.dart'; - -/// Object specifying creation parameters for creating a [WindowsWebMessageChannel]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebMessageChannelCreationParams] for -/// more information. -@immutable -class WindowsWebMessageChannelCreationParams - extends PlatformWebMessageChannelCreationParams { - /// Creates a new [WindowsWebMessageChannelCreationParams] instance. - const WindowsWebMessageChannelCreationParams( - {required super.id, required super.port1, required super.port2}); - - /// Creates a [WindowsWebMessageChannelCreationParams] instance based on [PlatformWebMessageChannelCreationParams]. - factory WindowsWebMessageChannelCreationParams.fromPlatformWebMessageChannelCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebMessageChannelCreationParams params) { - return WindowsWebMessageChannelCreationParams( - id: params.id, port1: params.port1, port2: params.port2); - } - - @override - String toString() { - return 'MacOSWebMessageChannelCreationParams{id: $id, port1: $port1, port2: $port2}'; - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageChannel} -class WindowsWebMessageChannel extends PlatformWebMessageChannel - with ChannelController { - /// Constructs a [WindowsWebMessageChannel]. - WindowsWebMessageChannel(PlatformWebMessageChannelCreationParams params) - : super.implementation( - params is WindowsWebMessageChannelCreationParams - ? params - : WindowsWebMessageChannelCreationParams - .fromPlatformWebMessageChannelCreationParams(params), - ) { - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_web_message_channel_${params.id}'); - handler = _handleMethod; - initMethodCallHandler(); - } - - static final WindowsWebMessageChannel _staticValue = WindowsWebMessageChannel( - WindowsWebMessageChannelCreationParams( - id: '', - port1: WindowsWebMessagePort( - WindowsWebMessagePortCreationParams(index: 0)), - port2: WindowsWebMessagePort( - WindowsWebMessagePortCreationParams(index: 1)))); - - /// Provide static access. - factory WindowsWebMessageChannel.static() { - return _staticValue; - } - - WindowsWebMessagePort get _macosPort1 => port1 as WindowsWebMessagePort; - - WindowsWebMessagePort get _macosPort2 => port2 as WindowsWebMessagePort; - - static WindowsWebMessageChannel? _fromMap(Map? map) { - if (map == null) { - return null; - } - var webMessageChannel = WindowsWebMessageChannel( - WindowsWebMessageChannelCreationParams( - id: map["id"], - port1: WindowsWebMessagePort( - WindowsWebMessagePortCreationParams(index: 0)), - port2: WindowsWebMessagePort( - WindowsWebMessagePortCreationParams(index: 1)))); - webMessageChannel._macosPort1.webMessageChannel = webMessageChannel; - webMessageChannel._macosPort2.webMessageChannel = webMessageChannel; - return webMessageChannel; - } - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onMessage": - int index = call.arguments["index"]; - var port = index == 0 ? _macosPort1 : _macosPort2; - if (port.onMessage != null) { - WebMessage? message = call.arguments["message"] != null - ? WebMessage.fromMap( - call.arguments["message"].cast()) - : null; - port.onMessage!(message); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - @override - WindowsWebMessageChannel? fromMap(Map? map) { - return _fromMap(map); - } - - @override - void dispose() { - disposeChannel(); - } - - @override - String toString() { - return 'MacOSWebMessageChannel{id: $id, port1: $port1, port2: $port2}'; - } -} - -extension InternalWebMessageChannel on WindowsWebMessageChannel { - MethodChannel? get internalChannel => channel; -} diff --git a/flutter_inappwebview_windows/lib/src/web_message/web_message_listener.dart b/flutter_inappwebview_windows/lib/src/web_message/web_message_listener.dart deleted file mode 100644 index 22a9cd768..000000000 --- a/flutter_inappwebview_windows/lib/src/web_message/web_message_listener.dart +++ /dev/null @@ -1,164 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -/// Object specifying creation parameters for creating a [WindowsWebMessageListener]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebMessageListenerCreationParams] for -/// more information. -@immutable -class WindowsWebMessageListenerCreationParams - extends PlatformWebMessageListenerCreationParams { - /// Creates a new [WindowsWebMessageListenerCreationParams] instance. - const WindowsWebMessageListenerCreationParams( - {required this.allowedOriginRules, - required super.jsObjectName, - super.onPostMessage}); - - /// Creates a [WindowsWebMessageListenerCreationParams] instance based on [PlatformWebMessageListenerCreationParams]. - factory WindowsWebMessageListenerCreationParams.fromPlatformWebMessageListenerCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebMessageListenerCreationParams params) { - return WindowsWebMessageListenerCreationParams( - allowedOriginRules: params.allowedOriginRules ?? Set.from(["*"]), - jsObjectName: params.jsObjectName, - onPostMessage: params.onPostMessage); - } - - @override - final Set allowedOriginRules; - - @override - String toString() { - return 'MacOSWebMessageListenerCreationParams{jsObjectName: $jsObjectName, allowedOriginRules: $allowedOriginRules, onPostMessage: $onPostMessage}'; - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessageListener} -class WindowsWebMessageListener extends PlatformWebMessageListener - with ChannelController { - /// Constructs a [WindowsWebMessageListener]. - WindowsWebMessageListener(PlatformWebMessageListenerCreationParams params) - : super.implementation( - params is WindowsWebMessageListenerCreationParams - ? params - : WindowsWebMessageListenerCreationParams - .fromPlatformWebMessageListenerCreationParams(params), - ) { - assert(!this._macosParams.allowedOriginRules.contains(""), - "allowedOriginRules cannot contain empty strings"); - channel = MethodChannel( - 'com.pichillilorenzo/flutter_inappwebview_web_message_listener_${_id}_${params.jsObjectName}'); - handler = _handleMethod; - initMethodCallHandler(); - } - - ///Message Listener ID used internally. - final String _id = IdGenerator.generate(); - - MacOSJavaScriptReplyProxy? _replyProxy; - - WindowsWebMessageListenerCreationParams get _macosParams => - params as WindowsWebMessageListenerCreationParams; - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case "onPostMessage": - if (_replyProxy == null) { - _replyProxy = MacOSJavaScriptReplyProxy( - PlatformJavaScriptReplyProxyCreationParams( - webMessageListener: this)); - } - if (onPostMessage != null) { - WebMessage? message = call.arguments["message"] != null - ? WebMessage.fromMap( - call.arguments["message"].cast()) - : null; - WebUri? sourceOrigin = call.arguments["sourceOrigin"] != null - ? WebUri(call.arguments["sourceOrigin"]) - : null; - bool isMainFrame = call.arguments["isMainFrame"]; - onPostMessage!(message, sourceOrigin, isMainFrame, _replyProxy!); - } - break; - default: - throw UnimplementedError("Unimplemented ${call.method} method"); - } - return null; - } - - @override - void dispose() { - disposeChannel(); - } - - @override - Map toMap() { - return { - "id": _id, - "jsObjectName": params.jsObjectName, - "allowedOriginRules": _macosParams.allowedOriginRules.toList(), - }; - } - - @override - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return 'MacOSWebMessageListener{id: ${_id}, jsObjectName: ${params.jsObjectName}, allowedOriginRules: ${params.allowedOriginRules}, replyProxy: $_replyProxy}'; - } -} - -/// Object specifying creation parameters for creating a [MacOSJavaScriptReplyProxy]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformJavaScriptReplyProxyCreationParams] for -/// more information. -@immutable -class MacOSJavaScriptReplyProxyCreationParams - extends PlatformJavaScriptReplyProxyCreationParams { - /// Creates a new [MacOSJavaScriptReplyProxyCreationParams] instance. - const MacOSJavaScriptReplyProxyCreationParams( - {required super.webMessageListener}); - - /// Creates a [MacOSJavaScriptReplyProxyCreationParams] instance based on [PlatformJavaScriptReplyProxyCreationParams]. - factory MacOSJavaScriptReplyProxyCreationParams.fromPlatformJavaScriptReplyProxyCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformJavaScriptReplyProxyCreationParams params) { - return MacOSJavaScriptReplyProxyCreationParams( - webMessageListener: params.webMessageListener); - } -} - -///{@macro flutter_inappwebview_platform_interface.JavaScriptReplyProxy} -class MacOSJavaScriptReplyProxy extends PlatformJavaScriptReplyProxy { - /// Constructs a [WindowsWebMessageListener]. - MacOSJavaScriptReplyProxy(PlatformJavaScriptReplyProxyCreationParams params) - : super.implementation( - params is MacOSJavaScriptReplyProxyCreationParams - ? params - : MacOSJavaScriptReplyProxyCreationParams - .fromPlatformJavaScriptReplyProxyCreationParams(params), - ); - - WindowsWebMessageListener get _macosWebMessageListener => - params.webMessageListener as WindowsWebMessageListener; - - @override - Future postMessage(WebMessage message) async { - Map args = {}; - args.putIfAbsent('message', () => message.toMap()); - await _macosWebMessageListener.channel?.invokeMethod('postMessage', args); - } - - @override - String toString() { - return 'MacOSJavaScriptReplyProxy{}'; - } -} diff --git a/flutter_inappwebview_windows/lib/src/web_message/web_message_port.dart b/flutter_inappwebview_windows/lib/src/web_message/web_message_port.dart deleted file mode 100644 index f75c956ea..000000000 --- a/flutter_inappwebview_windows/lib/src/web_message/web_message_port.dart +++ /dev/null @@ -1,95 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview_platform_interface/flutter_inappwebview_platform_interface.dart'; - -import 'web_message_channel.dart'; - -/// Object specifying creation parameters for creating a [WindowsWebMessagePort]. -/// -/// When adding additional fields make sure they can be null or have a default -/// value to avoid breaking changes. See [PlatformWebMessagePortCreationParams] for -/// more information. -@immutable -class WindowsWebMessagePortCreationParams - extends PlatformWebMessagePortCreationParams { - /// Creates a new [WindowsWebMessagePortCreationParams] instance. - const WindowsWebMessagePortCreationParams({required super.index}); - - /// Creates a [WindowsWebMessagePortCreationParams] instance based on [PlatformWebMessagePortCreationParams]. - factory WindowsWebMessagePortCreationParams.fromPlatformWebMessagePortCreationParams( - // Recommended placeholder to prevent being broken by platform interface. - // ignore: avoid_unused_constructor_parameters - PlatformWebMessagePortCreationParams params) { - return WindowsWebMessagePortCreationParams(index: params.index); - } - - @override - String toString() { - return 'MacOSWebMessagePortCreationParams{index: $index}'; - } -} - -///{@macro flutter_inappwebview_platform_interface.PlatformWebMessagePort} -class WindowsWebMessagePort extends PlatformWebMessagePort { - WebMessageCallback? _onMessage; - late WindowsWebMessageChannel _webMessageChannel; - - /// Constructs a [WindowsWebMessagePort]. - WindowsWebMessagePort(PlatformWebMessagePortCreationParams params) - : super.implementation( - params is WindowsWebMessagePortCreationParams - ? params - : WindowsWebMessagePortCreationParams - .fromPlatformWebMessagePortCreationParams(params), - ); - - @override - Future setWebMessageCallback(WebMessageCallback? onMessage) async { - Map args = {}; - args.putIfAbsent('index', () => params.index); - await _webMessageChannel.internalChannel - ?.invokeMethod('setWebMessageCallback', args); - this._onMessage = onMessage; - } - - @override - Future postMessage(WebMessage message) async { - Map args = {}; - args.putIfAbsent('index', () => params.index); - args.putIfAbsent('message', () => message.toMap()); - await _webMessageChannel.internalChannel?.invokeMethod('postMessage', args); - } - - @override - Future close() async { - Map args = {}; - args.putIfAbsent('index', () => params.index); - await _webMessageChannel.internalChannel?.invokeMethod('close', args); - } - - @override - Map toMap() { - return { - "index": params.index, - "webMessageChannelId": this._webMessageChannel.params.id - }; - } - - @override - Map toJson() { - return toMap(); - } - - @override - String toString() { - return 'MacOSWebMessagePort{index: ${params.index}}'; - } -} - -extension InternalWebMessagePort on WindowsWebMessagePort { - WebMessageCallback? get onMessage => _onMessage; - void set onMessage(WebMessageCallback? value) => _onMessage = value; - - WindowsWebMessageChannel get webMessageChannel => _webMessageChannel; - void set webMessageChannel(WindowsWebMessageChannel value) => - _webMessageChannel = value; -} diff --git a/flutter_inappwebview_windows/lib/src/web_storage/main.dart b/flutter_inappwebview_windows/lib/src/web_storage/main.dart index 7265ae52c..dab327ba6 100644 --- a/flutter_inappwebview_windows/lib/src/web_storage/main.dart +++ b/flutter_inappwebview_windows/lib/src/web_storage/main.dart @@ -1,2 +1,2 @@ export 'web_storage.dart'; -export 'web_storage_manager.dart' hide InternalWebStorageManager; +export 'web_storage_manager.dart'; diff --git a/flutter_inappwebview_windows/lib/src/web_storage/web_storage_manager.dart b/flutter_inappwebview_windows/lib/src/web_storage/web_storage_manager.dart index cd9c24e61..e4835bc11 100644 --- a/flutter_inappwebview_windows/lib/src/web_storage/web_storage_manager.dart +++ b/flutter_inappwebview_windows/lib/src/web_storage/web_storage_manager.dart @@ -39,7 +39,7 @@ class WindowsWebStorageManager extends PlatformWebStorageManager ) { channel = const MethodChannel( 'com.pichillilorenzo/flutter_inappwebview_webstoragemanager'); - handler = handleMethod; + handler = _handleMethod; initMethodCallHandler(); } @@ -56,6 +56,15 @@ class WindowsWebStorageManager extends PlatformWebStorageManager return _instance!; } + static WindowsWebStorageManager? _static; + + /// Provide static access. + factory WindowsWebStorageManager.static() { + _static ??= WindowsWebStorageManager(WindowsWebStorageManagerCreationParams( + const PlatformWebStorageManagerCreationParams())); + return _static!; + } + Future _handleMethod(MethodCall call) async {} @override @@ -128,7 +137,3 @@ class WindowsWebStorageManager extends PlatformWebStorageManager // empty } } - -extension InternalWebStorageManager on WindowsWebStorageManager { - get handleMethod => _handleMethod; -} diff --git a/flutter_inappwebview_windows/lib/src/webview_environment/webview_environment.dart b/flutter_inappwebview_windows/lib/src/webview_environment/webview_environment.dart index 4313b9749..482c9f332 100644 --- a/flutter_inappwebview_windows/lib/src/webview_environment/webview_environment.dart +++ b/flutter_inappwebview_windows/lib/src/webview_environment/webview_environment.dart @@ -61,12 +61,59 @@ class WindowsWebViewEnvironment extends PlatformWebViewEnvironment } switch (call.method) { + case 'onNewBrowserVersionAvailable': + if (onNewBrowserVersionAvailable != null) { + onNewBrowserVersionAvailable?.call(); + } + break; + case 'onBrowserProcessExited': + if (onBrowserProcessExited != null) { + Map arguments = + call.arguments.cast(); + final detail = BrowserProcessExitedDetail.fromMap(arguments)!; + onBrowserProcessExited?.call(detail); + } + break; + case 'onProcessInfosChanged': + if (onProcessInfosChanged != null) { + Map arguments = + call.arguments.cast(); + final detail = BrowserProcessInfosChangedDetail.fromMap(arguments)!; + onProcessInfosChanged?.call(detail); + } default: throw UnimplementedError("Unimplemented ${call.method} method"); } return null; } + @override + Future isInterfaceSupported(WebViewInterface interface) async { + Map args = {}; + args.putIfAbsent('interface', () => interface.toNativeValue()); + return await channel?.invokeMethod('isInterfaceSupported', args) ?? + false; + } + + @override + Future> getProcessInfos() async { + Map args = {}; + final result = + await channel?.invokeMethod>('getProcessInfos', args); + return result + ?.map((e) => BrowserProcessInfo.fromMap(e.cast())) + .whereType() + .toList() ?? + []; + } + + @override + Future getFailureReportFolderPath() async { + Map args = {}; + return await channel?.invokeMethod( + 'getFailureReportFolderPath', args); + } + @override Future create( {WebViewEnvironmentSettings? settings}) async { @@ -78,8 +125,8 @@ class WindowsWebViewEnvironment extends PlatformWebViewEnvironment args.putIfAbsent('settings', () => env.settings?.toMap()); await _staticChannel.invokeMethod('create', args); - env.channel = - MethodChannel('com.pichillilorenzo/flutter_webview_environment_$id'); + env.channel = MethodChannel( + 'com.pichillilorenzo/flutter_webview_environment_${env.id}'); env.handler = env.handleMethod; env.initMethodCallHandler(); return env; diff --git a/flutter_inappwebview_windows/pubspec.yaml b/flutter_inappwebview_windows/pubspec.yaml index ed5710fcb..0ebc13a87 100644 --- a/flutter_inappwebview_windows/pubspec.yaml +++ b/flutter_inappwebview_windows/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_inappwebview_windows description: Windows implementation of the flutter_inappwebview plugin. -version: 0.5.0+2 +version: 0.7.0-beta.3 homepage: https://inappwebview.dev/ repository: https://github.com/pichillilorenzo/flutter_inappwebview/tree/master/flutter_inappwebview_windows issue_tracker: https://github.com/pichillilorenzo/flutter_inappwebview/issues @@ -20,7 +20,8 @@ environment: dependencies: flutter: sdk: flutter - flutter_inappwebview_platform_interface: ^1.3.0 + flutter_inappwebview_platform_interface: #^1.4.0-beta.3 + path: ../flutter_inappwebview_platform_interface dev_dependencies: flutter_test: diff --git a/flutter_inappwebview_windows/windows/CMakeLists.txt b/flutter_inappwebview_windows/windows/CMakeLists.txt index adfbbf787..666fbbe08 100644 --- a/flutter_inappwebview_windows/windows/CMakeLists.txt +++ b/flutter_inappwebview_windows/windows/CMakeLists.txt @@ -5,8 +5,9 @@ cmake_minimum_required(VERSION 3.14) set(WIL_VERSION "1.0.231216.1") -set(WEBVIEW_VERSION "1.0.2792.45") -set(NLOHMANN_JSON "3.11.2") +set(WEBVIEW_VERSION "1.0.2849.39") +set(NLOHMANN_JSON_VERSION "3.11.2") +set(CPP_WINRT_VERSION "2.0.240405.15") message(VERBOSE "CMake system version is ${CMAKE_SYSTEM_VERSION} (using SDK ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION})") @@ -27,12 +28,13 @@ if(NOT NUGET) message(NOTICE "Nuget is not installed! The flutter_inappwebview_windows plugin requires it. Check https://inappwebview.dev/docs/intro#setup-windows") endif() -add_custom_target(${PROJECT_NAME}_DEPENDENCIES_DOWNLOAD ALL) +add_custom_target(${PROJECT_NAME}_DEPS ALL) add_custom_command( - TARGET ${PROJECT_NAME}_DEPENDENCIES_DOWNLOAD PRE_BUILD + TARGET ${PROJECT_NAME}_DEPS PRE_BUILD COMMAND ${NUGET} install Microsoft.Windows.ImplementationLibrary -Version ${WIL_VERSION} -ExcludeVersion -OutputDirectory ${CMAKE_BINARY_DIR}/packages + COMMAND ${NUGET} install Microsoft.Windows.CppWinRT -Version ${CPP_WINRT_VERSION} -ExcludeVersion -OutputDirectory ${CMAKE_BINARY_DIR}/packages COMMAND ${NUGET} install Microsoft.Web.WebView2 -Version ${WEBVIEW_VERSION} -ExcludeVersion -OutputDirectory ${CMAKE_BINARY_DIR}/packages - COMMAND ${NUGET} install nlohmann.json -Version ${NLOHMANN_JSON} -ExcludeVersion -OutputDirectory ${CMAKE_BINARY_DIR}/packages + COMMAND ${NUGET} install nlohmann.json -Version ${NLOHMANN_JSON_VERSION} -ExcludeVersion -OutputDirectory ${CMAKE_BINARY_DIR}/packages DEPENDS ${NUGET} ) @@ -41,6 +43,8 @@ list(APPEND PLUGIN_SOURCES "flutter_inappwebview_windows_plugin.cpp" "flutter_inappwebview_windows_plugin.h" "utils/log.h" + "utils/defer.h" + "utils/timer.h" "utils/strconv.h" "utils/map.h" "utils/vector.h" @@ -49,6 +53,8 @@ list(APPEND PLUGIN_SOURCES "utils/flutter.h" "utils/base64.cpp" "utils/base64.h" + "utils/uri.h" + "utils/uuid.h" "types/channel_delegate.cpp" "types/channel_delegate.h" "types/base_callback_result.h" @@ -93,6 +99,50 @@ list(APPEND PLUGIN_SOURCES "types/custom_scheme_response.h" "types/custom_scheme_registration.cpp" "types/custom_scheme_registration.h" + "types/javascript_handler_function_data.cpp" + "types/javascript_handler_function_data.h" + "types/ssl_error.cpp" + "types/ssl_error.h" + "types/url_credential.cpp" + "types/url_credential.h" + "types/url_protection_space.cpp" + "types/url_protection_space.h" + "types/url_authentication_challenge.cpp" + "types/url_authentication_challenge.h" + "types/http_authentication_challenge.cpp" + "types/http_authentication_challenge.h" + "types/http_auth_response.cpp" + "types/http_auth_response.h" + "types/client_cert_challenge.cpp" + "types/client_cert_challenge.h" + "types/client_cert_response.cpp" + "types/client_cert_response.h" + "types/server_trust_challenge.cpp" + "types/server_trust_challenge.h" + "types/server_trust_auth_response.cpp" + "types/server_trust_auth_response.h" + "types/security_origin.cpp" + "types/security_origin.h" + "types/frame_info.cpp" + "types/frame_info.h" + "types/process_failed_detail.cpp" + "types/process_failed_detail.h" + "types/render_process_gone_detail.cpp" + "types/render_process_gone_detail.h" + "types/download_start_request.cpp" + "types/download_start_request.h" + "types/download_start_response.cpp" + "types/download_start_response.h" + "types/browser_process_exited_detail.cpp" + "types/browser_process_exited_detail.h" + "types/browser_process_info.cpp" + "types/browser_process_info.h" + "types/browser_process_infos_changed_detail.cpp" + "types/browser_process_infos_changed_detail.h" + "types/physical_key_status.cpp" + "types/physical_key_status.h" + "types/accelerator_key_pressed_detail.cpp" + "types/accelerator_key_pressed_detail.h" "custom_platform_view/custom_platform_view.cc" "custom_platform_view/custom_platform_view.h" "custom_platform_view/texture_bridge.cc" @@ -107,7 +157,6 @@ list(APPEND PLUGIN_SOURCES "custom_platform_view/util/string_converter.h" "custom_platform_view/util/swizzle.h" "plugin_scripts_js/plugin_scripts_util.h" - "plugin_scripts_js/javascript_bridge_js.cpp" "plugin_scripts_js/javascript_bridge_js.h" "webview_environment/webview_environment_settings.cpp" "webview_environment/webview_environment_settings.h" @@ -143,6 +192,8 @@ list(APPEND PLUGIN_SOURCES "in_app_browser/in_app_browser_channel_delegate.h" "cookie_manager.cpp" "cookie_manager.h" + "platform_util.cpp" + "platform_util.h" ) # Define the plugin library target. Its name must not be changed (see comment @@ -184,10 +235,12 @@ endif() # IMPORTANT: The apply_standard_settings function is not used here because it # is causing the plugin to fail to compile because of the usage of /WX flag. # So, creating here a custom function to apply the standard settings without the /WX flag. +# Also, added /bigobj flag. function(FLUTTER_INAPPWEBVIEW_WINDOWS_APPLY_STANDARD_SETTINGS TARGET) target_compile_features(${TARGET} PUBLIC cxx_std_17) target_compile_options(${TARGET} PRIVATE /W4 /wd"4100") target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_options(${TARGET} PRIVATE /bigobj) target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") endfunction() diff --git a/flutter_inappwebview_windows/windows/cookie_manager.cpp b/flutter_inappwebview_windows/windows/cookie_manager.cpp index 2fa0eb5d3..2c1026143 100644 --- a/flutter_inappwebview_windows/windows/cookie_manager.cpp +++ b/flutter_inappwebview_windows/windows/cookie_manager.cpp @@ -1,13 +1,14 @@ -#include #include -#include -#include -#include #include "cookie_manager.h" +#include "headless_in_app_webview/headless_in_app_webview_manager.h" +#include "in_app_browser/in_app_browser_manager.h" +#include "in_app_webview/in_app_webview_manager.h" #include "types/callbacks_complete.h" #include "utils/flutter.h" #include "utils/log.h" +#include "utils/timer.h" + namespace flutter_inappwebview_plugin { @@ -25,11 +26,29 @@ namespace flutter_inappwebview_plugin auto webViewEnvironmentId = get_optional_fl_map_value(arguments, "webViewEnvironmentId"); - auto webViewEnvironment = webViewEnvironmentId.has_value() && map_contains(plugin->webViewEnvironmentManager->webViewEnvironments, webViewEnvironmentId.value()) + auto webViewEnvironment = plugin && webViewEnvironmentId.has_value() && map_contains(plugin->webViewEnvironmentManager->webViewEnvironments, webViewEnvironmentId.value()) ? plugin->webViewEnvironmentManager->webViewEnvironments.at(webViewEnvironmentId.value()).get() : nullptr; + InAppWebView* webView = nullptr; + auto webViewIdInt = get_optional_fl_map_value(arguments, "webViewId"); + auto webViewIdString = !webViewIdInt.has_value() ? get_optional_fl_map_value(arguments, "webViewId") : std::optional{}; + if (webViewIdInt.has_value() && plugin->inAppWebViewManager && map_contains(plugin->inAppWebViewManager->webViews, (uint64_t)webViewIdInt.value())) { + webView = plugin->inAppWebViewManager->webViews.at(webViewIdInt.value())->view.get(); + } + else if (webViewIdString.has_value()) { + if (plugin->inAppWebViewManager && map_contains(plugin->inAppWebViewManager->keepAliveWebViews, webViewIdString.value())) { + webView = plugin->inAppWebViewManager->keepAliveWebViews.at(webViewIdString.value())->view.get(); + } + else if (plugin->headlessInAppWebViewManager && map_contains(plugin->headlessInAppWebViewManager->webViews, webViewIdString.value())) { + webView = plugin->headlessInAppWebViewManager->webViews.at(webViewIdString.value())->webView.get(); + } + else if (plugin->inAppBrowserManager && map_contains(plugin->inAppBrowserManager->browsers, webViewIdString.value())) { + webView = plugin->inAppBrowserManager->browsers.at(webViewIdString.value())->webView.get(); + } + } + auto result_ = std::shared_ptr>(std::move(result)); - auto callback = [this, result_, methodName, arguments](WebViewEnvironment* webViewEnvironment) + auto callback = [this, result_, methodName, arguments, webView](WebViewEnvironment* webViewEnvironment) { if (!webViewEnvironment) { result_->Error("0", "Cannot obtain the WebViewEnvironment!"); @@ -37,7 +56,7 @@ namespace flutter_inappwebview_plugin } if (string_equals(methodName, "setCookie")) { - setCookie(webViewEnvironment, arguments, [result_](const bool& created) + setCookie(webViewEnvironment, webView, arguments, [result_](const bool& created) { result_->Success(created); }); @@ -45,14 +64,14 @@ namespace flutter_inappwebview_plugin else if (string_equals(methodName, "getCookie")) { auto url = get_fl_map_value(arguments, "url"); auto name = get_fl_map_value(arguments, "name"); - getCookie(webViewEnvironment, url, name, [result_](const flutter::EncodableValue& cookie) + getCookie(webViewEnvironment, webView, url, name, [result_](const flutter::EncodableValue& cookie) { result_->Success(cookie); }); } else if (string_equals(methodName, "getCookies")) { auto url = get_fl_map_value(arguments, "url"); - getCookies(webViewEnvironment, url, [result_](const flutter::EncodableList& cookies) + getCookies(webViewEnvironment, webView, url, [result_](const flutter::EncodableList& cookies) { result_->Success(cookies); }); @@ -62,7 +81,7 @@ namespace flutter_inappwebview_plugin auto name = get_fl_map_value(arguments, "name"); auto path = get_fl_map_value(arguments, "path"); auto domain = get_optional_fl_map_value(arguments, "domain"); - deleteCookie(webViewEnvironment, url, name, path, domain, [result_](const bool& deleted) + deleteCookie(webViewEnvironment, webView, url, name, path, domain, [result_](const bool& deleted) { result_->Success(deleted); }); @@ -71,7 +90,7 @@ namespace flutter_inappwebview_plugin auto url = get_fl_map_value(arguments, "url"); auto path = get_fl_map_value(arguments, "path"); auto domain = get_optional_fl_map_value(arguments, "domain"); - deleteCookies(webViewEnvironment, url, path, domain, [result_](const bool& deleted) + deleteCookies(webViewEnvironment, webView, url, path, domain, [result_](const bool& deleted) { result_->Success(deleted); }); @@ -98,7 +117,7 @@ namespace flutter_inappwebview_plugin } } - void CookieManager::setCookie(WebViewEnvironment* webViewEnvironment, const flutter::EncodableMap& map, std::function completionHandler) const + void CookieManager::setCookie(WebViewEnvironment* webViewEnvironment, InAppWebView* inAppWebView, const flutter::EncodableMap& map, std::function completionHandler) const { if (!plugin || !plugin->webViewEnvironmentManager) { if (completionHandler) { @@ -144,22 +163,61 @@ namespace flutter_inappwebview_plugin parameters["sameSite"] = sameSite.value(); } - auto hr = webViewEnvironment->getWebView()->CallDevToolsProtocolMethod(L"Network.setCookie", utf8_to_wide(parameters.dump()).c_str(), Callback( - [completionHandler](HRESULT errorCode, LPCWSTR returnObjectAsJson) + auto callback = [=](wil::com_ptr webViewController, wil::com_ptr webView, bool shouldDestroyWebView) { - if (completionHandler) { - completionHandler(succeededOrLog(errorCode)); + if (!webView) { + completionHandler(false); + if (shouldDestroyWebView && webViewController) { + webViewController->Close(); + } + return; } - return S_OK; - } - ).Get()); - if (failedAndLog(hr) && completionHandler) { - completionHandler(false); + auto hr = webView->CallDevToolsProtocolMethod(L"Network.setCookie", utf8_to_wide(parameters.dump()).c_str(), Callback( + [=](HRESULT errorCode, LPCWSTR returnObjectAsJson) + { + if (completionHandler) { + completionHandler(succeededOrLog(errorCode)); + } + + if (shouldDestroyWebView && webViewController) { + // for an unknown reason, destroying the temp webview just here, after + // the execution of this method, causes a crash inside ICoreWebView2, + // so we destroy it just after 1 second. + Timer::setTimeout([webViewController]() + { + if (webViewController) { + webViewController->Close(); + } + }, 1000); + } + + return S_OK; + } + ).Get()); + + if (failedAndLog(hr)) { + if (completionHandler) { + completionHandler(false); + } + if (shouldDestroyWebView && webViewController) { + webViewController->Close(); + } + } + }; + + if (inAppWebView && inAppWebView->webView) { + callback(nullptr, inAppWebView->webView, false); + } + else { + webViewEnvironment->useTempWebView([this, callback](wil::com_ptr webViewController, wil::com_ptr webView) + { + callback(webViewController, webView, true); + }); } } - void CookieManager::getCookie(WebViewEnvironment* webViewEnvironment, const std::string& url, const std::string& name, std::function completionHandler) const + void CookieManager::getCookie(WebViewEnvironment* webViewEnvironment, InAppWebView* inAppWebView, const std::string& url, const std::string& name, std::function completionHandler) const { if (!plugin || !plugin->webViewEnvironmentManager) { if (completionHandler) { @@ -172,43 +230,82 @@ namespace flutter_inappwebview_plugin {"urls", std::vector{url}} }; - auto hr = webViewEnvironment->getWebView()->CallDevToolsProtocolMethod(L"Network.getCookies", utf8_to_wide(parameters.dump()).c_str(), Callback( - [completionHandler, name](HRESULT errorCode, LPCWSTR returnObjectAsJson) + auto callback = [=](wil::com_ptr webViewController, wil::com_ptr webView, bool shouldDestroyWebView) { - if (succeededOrLog(errorCode)) { - nlohmann::json json = nlohmann::json::parse(wide_to_utf8(returnObjectAsJson)); - auto jsonCookies = json["cookies"].get>(); - for (auto& jsonCookie : jsonCookies) { - auto cookieName = jsonCookie["name"].get(); - if (string_equals(name, cookieName)) { - completionHandler(flutter::EncodableMap{ - {"name", cookieName}, - {"value", jsonCookie["value"].get()}, - {"domain", jsonCookie["domain"].get()}, - {"path", jsonCookie["path"].get()}, - {"expiresDate", jsonCookie["expires"].get()}, - {"isHttpOnly", jsonCookie["httpOnly"].get()}, - {"isSecure", jsonCookie["secure"].get()}, - {"isSessionOnly", jsonCookie["session"].get()}, - {"sameSite", jsonCookie.contains("sameSite") ? jsonCookie["sameSite"].get() : make_fl_value()} - }); - return S_OK; - } + if (!webView) { + completionHandler(make_fl_value()); + if (shouldDestroyWebView && webViewController) { + webViewController->Close(); } + return; } - if (completionHandler) { - completionHandler(make_fl_value()); + + auto hr = webView->CallDevToolsProtocolMethod(L"Network.getCookies", utf8_to_wide(parameters.dump()).c_str(), Callback( + [=](HRESULT errorCode, LPCWSTR returnObjectAsJson) + { + if (succeededOrLog(errorCode)) { + nlohmann::json json = nlohmann::json::parse(wide_to_utf8(returnObjectAsJson)); + auto jsonCookies = json["cookies"].get>(); + for (auto& jsonCookie : jsonCookies) { + auto cookieName = jsonCookie["name"].get(); + if (string_equals(name, cookieName)) { + completionHandler(flutter::EncodableMap{ + {"name", cookieName}, + {"value", jsonCookie["value"].get()}, + {"domain", jsonCookie["domain"].get()}, + {"path", jsonCookie["path"].get()}, + {"expiresDate", jsonCookie["expires"].get()}, + {"isHttpOnly", jsonCookie["httpOnly"].get()}, + {"isSecure", jsonCookie["secure"].get()}, + {"isSessionOnly", jsonCookie["session"].get()}, + {"sameSite", jsonCookie.contains("sameSite") ? jsonCookie["sameSite"].get() : make_fl_value()} + }); + return S_OK; + } + } + } + if (completionHandler) { + completionHandler(make_fl_value()); + } + + if (shouldDestroyWebView && webViewController) { + // for an unknown reason, destroying the temp webview just here, after + // the execution of this method, causes a crash inside ICoreWebView2, + // so we destroy it just after 1 second. + Timer::setTimeout([webViewController]() + { + if (webViewController) { + webViewController->Close(); + } + }, 1000); + } + + return S_OK; + } + ).Get()); + + if (failedAndLog(hr)) { + if (completionHandler) { + completionHandler(make_fl_value()); + } + if (shouldDestroyWebView && webViewController) { + webViewController->Close(); + } } - return S_OK; - } - ).Get()); + }; - if (failedAndLog(hr) && completionHandler) { - completionHandler(make_fl_value()); + if (inAppWebView && inAppWebView->webView) { + callback(nullptr, inAppWebView->webView, false); + } + else { + webViewEnvironment->useTempWebView([callback](wil::com_ptr webViewController, wil::com_ptr webView) + { + callback(webViewController, webView, true); + }); } } - void CookieManager::getCookies(WebViewEnvironment* webViewEnvironment, const std::string& url, std::function completionHandler) const + void CookieManager::getCookies(WebViewEnvironment* webViewEnvironment, InAppWebView* inAppWebView, const std::string& url, std::function completionHandler) const { if (!plugin || !plugin->webViewEnvironmentManager) { if (completionHandler) { @@ -221,40 +318,80 @@ namespace flutter_inappwebview_plugin {"urls", std::vector{url}} }; - auto hr = webViewEnvironment->getWebView()->CallDevToolsProtocolMethod(L"Network.getCookies", utf8_to_wide(parameters.dump()).c_str(), Callback( - [completionHandler](HRESULT errorCode, LPCWSTR returnObjectAsJson) + auto callback = [=](wil::com_ptr webViewController, wil::com_ptr webView, bool shouldDestroyWebView) { - std::vector cookies = {}; - if (succeededOrLog(errorCode)) { - nlohmann::json json = nlohmann::json::parse(wide_to_utf8(returnObjectAsJson)); - auto jsonCookies = json["cookies"].get>(); - for (auto& jsonCookie : jsonCookies) { - cookies.push_back(flutter::EncodableMap{ - {"name", jsonCookie["name"].get()}, - {"value", jsonCookie["value"].get()}, - {"domain", jsonCookie["domain"].get()}, - {"path", jsonCookie["path"].get()}, - {"expiresDate", jsonCookie["expires"].get()}, - {"isHttpOnly", jsonCookie["httpOnly"].get()}, - {"isSecure", jsonCookie["secure"].get()}, - {"isSessionOnly", jsonCookie["session"].get()}, - {"sameSite", jsonCookie.contains("sameSite") ? jsonCookie["sameSite"].get() : make_fl_value()} - }); + if (!webView) { + completionHandler({}); + if (shouldDestroyWebView && webViewController) { + webViewController->Close(); } + return; } - if (completionHandler) { - completionHandler(cookies); + + auto hr = webView->CallDevToolsProtocolMethod(L"Network.getCookies", utf8_to_wide(parameters.dump()).c_str(), Callback( + [=](HRESULT errorCode, LPCWSTR returnObjectAsJson) + { + std::vector cookies = {}; + if (succeededOrLog(errorCode)) { + nlohmann::json json = nlohmann::json::parse(wide_to_utf8(returnObjectAsJson)); + auto jsonCookies = json["cookies"].get>(); + for (auto& jsonCookie : jsonCookies) { + cookies.push_back(flutter::EncodableMap{ + {"name", jsonCookie["name"].get()}, + {"value", jsonCookie["value"].get()}, + {"domain", jsonCookie["domain"].get()}, + {"path", jsonCookie["path"].get()}, + {"expiresDate", jsonCookie["expires"].get()}, + {"isHttpOnly", jsonCookie["httpOnly"].get()}, + {"isSecure", jsonCookie["secure"].get()}, + {"isSessionOnly", jsonCookie["session"].get()}, + {"sameSite", jsonCookie.contains("sameSite") ? jsonCookie["sameSite"].get() : make_fl_value()} + }); + } + } + + if (completionHandler) { + completionHandler(cookies); + } + + if (shouldDestroyWebView && webViewController) { + // for an unknown reason, destroying the temp webview just here, after + // the execution of this method, causes a crash inside ICoreWebView2, + // so we destroy it just after 1 second. + Timer::setTimeout([webViewController]() + { + if (webViewController) { + webViewController->Close(); + } + }, 1000); + } + + return S_OK; + } + ).Get()); + + if (failedAndLog(hr)) { + if (completionHandler) { + completionHandler({}); + } + if (shouldDestroyWebView && webViewController) { + webViewController->Close(); + } } - return S_OK; - } - ).Get()); + }; - if (failedAndLog(hr) && completionHandler) { - completionHandler({}); + if (inAppWebView && inAppWebView->webView) { + callback(nullptr, inAppWebView->webView, false); + } + else { + webViewEnvironment->useTempWebView([callback](wil::com_ptr webViewController, wil::com_ptr webView) + { + callback(webViewController, webView, true); + }); } } - void CookieManager::deleteCookie(WebViewEnvironment* webViewEnvironment, const std::string& url, const std::string& name, const std::string& path, const std::optional& domain, std::function completionHandler) const + void CookieManager::deleteCookie(WebViewEnvironment* webViewEnvironment, InAppWebView* inAppWebView, const std::string& url, const std::string& name, const std::string& path, const std::optional& domain, std::function completionHandler) const { if (!plugin || !plugin->webViewEnvironmentManager) { if (completionHandler) { @@ -272,22 +409,61 @@ namespace flutter_inappwebview_plugin parameters["domain"] = domain.value(); } - auto hr = webViewEnvironment->getWebView()->CallDevToolsProtocolMethod(L"Network.deleteCookies", utf8_to_wide(parameters.dump()).c_str(), Callback( - [completionHandler](HRESULT errorCode, LPCWSTR returnObjectAsJson) + auto callback = [=](wil::com_ptr webViewController, wil::com_ptr webView, bool shouldDestroyWebView) { - if (completionHandler) { - completionHandler(succeededOrLog(errorCode)); + if (!webView) { + completionHandler(false); + if (shouldDestroyWebView && webViewController) { + webViewController->Close(); + } + return; } - return S_OK; - } - ).Get()); - if (failedAndLog(hr) && completionHandler) { - completionHandler(false); + auto hr = webView->CallDevToolsProtocolMethod(L"Network.deleteCookies", utf8_to_wide(parameters.dump()).c_str(), Callback( + [=](HRESULT errorCode, LPCWSTR returnObjectAsJson) + { + if (completionHandler) { + completionHandler(succeededOrLog(errorCode)); + } + + if (shouldDestroyWebView && webViewController) { + // for an unknown reason, destroying the temp webview just here, after + // the execution of this method, causes a crash inside ICoreWebView2, + // so we destroy it just after 1 second. + Timer::setTimeout([webViewController]() + { + if (webViewController) { + webViewController->Close(); + } + }, 1000); + } + + return S_OK; + } + ).Get()); + + if (failedAndLog(hr)) { + if (completionHandler) { + completionHandler(false); + } + if (shouldDestroyWebView && webViewController) { + webViewController->Close(); + } + } + }; + + if (inAppWebView && inAppWebView->webView) { + callback(nullptr, inAppWebView->webView, false); + } + else { + webViewEnvironment->useTempWebView([callback](wil::com_ptr webViewController, wil::com_ptr webView) + { + callback(webViewController, webView, true); + }); } } - void CookieManager::deleteCookies(WebViewEnvironment* webViewEnvironment, const std::string& url, const std::string& path, const std::optional& domain, std::function completionHandler) const + void CookieManager::deleteCookies(WebViewEnvironment* webViewEnvironment, InAppWebView* inAppWebView, const std::string& url, const std::string& path, const std::optional& domain, std::function completionHandler) const { if (!plugin || !plugin->webViewEnvironmentManager) { if (completionHandler) { @@ -296,7 +472,7 @@ namespace flutter_inappwebview_plugin return; } - getCookies(webViewEnvironment, url, [this, webViewEnvironment, url, path, domain, completionHandler](const flutter::EncodableList& cookies) + getCookies(webViewEnvironment, inAppWebView, url, [this, webViewEnvironment, inAppWebView, url, path, domain, completionHandler](const flutter::EncodableList& cookies) { auto callbacksComplete = std::make_shared>( [completionHandler](const std::vector& values) @@ -309,7 +485,7 @@ namespace flutter_inappwebview_plugin for (auto& cookie : cookies) { auto cookieMap = std::get(cookie); auto name = get_fl_map_value(cookieMap, "name"); - deleteCookie(webViewEnvironment, url, name, path, domain, [callbacksComplete](const bool& deleted) + deleteCookie(webViewEnvironment, inAppWebView, url, name, path, domain, [callbacksComplete](const bool& deleted) { callbacksComplete->addValue(deleted); }); @@ -317,7 +493,7 @@ namespace flutter_inappwebview_plugin }); } - void CookieManager::deleteAllCookies(WebViewEnvironment* webViewEnvironment, std::function completionHandler) const + void CookieManager::deleteAllCookies(WebViewEnvironment* webViewEnvironment, std::function completionHandler) { if (!plugin || !plugin->webViewEnvironmentManager) { if (completionHandler) { @@ -326,19 +502,53 @@ namespace flutter_inappwebview_plugin return; } - auto hr = webViewEnvironment->getWebView()->CallDevToolsProtocolMethod(L"Network.clearBrowserCookies", L"{}", Callback( - [completionHandler](HRESULT errorCode, LPCWSTR returnObjectAsJson) + auto callback = [=](wil::com_ptr webViewController, wil::com_ptr webView, bool shouldDestroyWebView) { - if (completionHandler) { - completionHandler(succeededOrLog(errorCode)); + if (!webView) { + completionHandler(false); + if (shouldDestroyWebView && webViewController) { + webViewController->Close(); + } + return; } - return S_OK; - } - ).Get()); - if (failedAndLog(hr) && completionHandler) { - completionHandler(false); - } + auto hr = webView->CallDevToolsProtocolMethod(L"Network.clearBrowserCookies", L"{}", Callback( + [=](HRESULT errorCode, LPCWSTR returnObjectAsJson) + { + if (completionHandler) { + completionHandler(succeededOrLog(errorCode)); + } + + if (shouldDestroyWebView && webViewController) { + // for an unknown reason, destroying the temp webview just here, after + // the execution of this method, causes a crash inside ICoreWebView2, + // so we destroy it just after 1 second. + Timer::setTimeout([webViewController]() + { + if (webViewController) { + webViewController->Close(); + } + }, 1000); + } + + return S_OK; + } + ).Get()); + + if (failedAndLog(hr)) { + if (completionHandler) { + completionHandler(false); + } + if (shouldDestroyWebView && webViewController) { + webViewController->Close(); + } + } + }; + + webViewEnvironment->useTempWebView([callback](wil::com_ptr webViewController, wil::com_ptr webView) + { + callback(webViewController, webView, true); + }); } CookieManager::~CookieManager() diff --git a/flutter_inappwebview_windows/windows/cookie_manager.h b/flutter_inappwebview_windows/windows/cookie_manager.h index 313fd8a2c..db0561247 100644 --- a/flutter_inappwebview_windows/windows/cookie_manager.h +++ b/flutter_inappwebview_windows/windows/cookie_manager.h @@ -7,6 +7,7 @@ #include #include "flutter_inappwebview_windows_plugin.h" +#include "in_app_webview/in_app_webview.h" #include "types/channel_delegate.h" #include "webview_environment/webview_environment_manager.h" @@ -26,12 +27,12 @@ namespace flutter_inappwebview_plugin const flutter::MethodCall& method_call, std::unique_ptr> result); - void setCookie(WebViewEnvironment* webViewEnvironment, const flutter::EncodableMap& map, std::function completionHandler) const; - void getCookie(WebViewEnvironment* webViewEnvironment, const std::string& url, const std::string& name, std::function completionHandler) const; - void getCookies(WebViewEnvironment* webViewEnvironment, const std::string& url, std::function completionHandler) const; - void deleteCookie(WebViewEnvironment* webViewEnvironment, const std::string& url, const std::string& name, const std::string& path, const std::optional& domain, std::function completionHandler) const; - void deleteCookies(WebViewEnvironment* webViewEnvironment, const std::string& url, const std::string& path, const std::optional& domain, std::function completionHandler) const; - void deleteAllCookies(WebViewEnvironment* webViewEnvironment, std::function completionHandler) const; + void setCookie(WebViewEnvironment* webViewEnvironment, InAppWebView* inAppWebView, const flutter::EncodableMap& map, std::function completionHandler) const; + void getCookie(WebViewEnvironment* webViewEnvironment, InAppWebView* inAppWebView, const std::string& url, const std::string& name, std::function completionHandler) const; + void getCookies(WebViewEnvironment* webViewEnvironment, InAppWebView* inAppWebView, const std::string& url, std::function completionHandler) const; + void deleteCookie(WebViewEnvironment* webViewEnvironment, InAppWebView* inAppWebView, const std::string& url, const std::string& name, const std::string& path, const std::optional& domain, std::function completionHandler) const; + void deleteCookies(WebViewEnvironment* webViewEnvironment, InAppWebView* inAppWebView, const std::string& url, const std::string& path, const std::optional& domain, std::function completionHandler) const; + void deleteAllCookies(WebViewEnvironment* webViewEnvironment, std::function completionHandler); }; } diff --git a/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.cc b/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.cc index 1b6a3ff88..f990fcc44 100644 --- a/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.cc +++ b/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.cc @@ -186,12 +186,21 @@ namespace flutter_inappwebview_plugin event_channel_->SetStreamHandler(std::move(handler)); } + void CustomPlatformView::UnregisterMethodCallHandler() const + { + if (method_channel_) { + method_channel_->SetMethodCallHandler(nullptr); + if (view && view->channelDelegate) { + view->channelDelegate->UnregisterMethodCallHandler(); + } + } + } + CustomPlatformView::~CustomPlatformView() { debugLog("dealloc CustomPlatformView"); - method_channel_->SetMethodCallHandler(nullptr); event_sink_ = nullptr; - texture_registrar_->UnregisterTexture(texture_id_); + texture_registrar_->UnregisterTexture(texture_id_, nullptr); } void CustomPlatformView::RegisterEventHandlers() @@ -273,14 +282,15 @@ namespace flutter_inappwebview_plugin if (method_name.compare(kMethodSetPointerButton) == 0) { const auto& map = std::get(*method_call.arguments()); + const auto kind = map.find(flutter::EncodableValue("kind")); const auto button = map.find(flutter::EncodableValue("button")); - const auto isDown = map.find(flutter::EncodableValue("isDown")); - if (button != map.end() && isDown != map.end()) { + if (kind != map.end() && button != map.end()) { + const auto kindValue = std::get_if(&kind->second); const auto buttonValue = std::get_if(&button->second); - const auto isDownValue = std::get_if(&isDown->second); - if (buttonValue && isDownValue && view) { + if (kindValue && buttonValue && view) { view->setPointerButtonState( - static_cast(*buttonValue), *isDownValue); + static_cast(*kindValue), + static_cast(*buttonValue)); return result->Success(); } } diff --git a/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.h b/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.h index 35946f340..65db5476a 100644 --- a/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.h +++ b/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.h @@ -29,6 +29,8 @@ namespace flutter_inappwebview_plugin TextureBridge* texture_bridge() const { return texture_bridge_.get(); } int64_t texture_id() const { return texture_id_; } + + void UnregisterMethodCallHandler() const; private: HWND hwnd_; std::unique_ptr flutter_texture_; diff --git a/flutter_inappwebview_windows/windows/flutter_inappwebview_windows_plugin.cpp b/flutter_inappwebview_windows/windows/flutter_inappwebview_windows_plugin.cpp index a616a89bd..ac829ae9f 100644 --- a/flutter_inappwebview_windows/windows/flutter_inappwebview_windows_plugin.cpp +++ b/flutter_inappwebview_windows/windows/flutter_inappwebview_windows_plugin.cpp @@ -6,11 +6,15 @@ #include "headless_in_app_webview/headless_in_app_webview_manager.h" #include "in_app_browser/in_app_browser_manager.h" #include "in_app_webview/in_app_webview_manager.h" +#include "platform_util.h" #include "webview_environment/webview_environment_manager.h" + #pragma comment(lib, "Shlwapi.lib") #pragma comment(lib, "dxgi.lib") #pragma comment(lib, "d3d11.lib") +#pragma comment(lib, "rpcrt4.lib") // UuidCreate - Minimum supported OS Win 2000 +#pragma comment(lib, "WindowsApp.lib") namespace flutter_inappwebview_plugin { @@ -30,8 +34,41 @@ namespace flutter_inappwebview_plugin inAppBrowserManager = std::make_unique(this); headlessInAppWebViewManager = std::make_unique(this); cookieManager = std::make_unique(this); + platformUtil = std::make_unique(this); + + window_proc_id = registrar->RegisterTopLevelWindowProcDelegate( + [this](HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) + { + return HandleWindowProc(hWnd, message, wParam, lParam); + }); } FlutterInappwebviewWindowsPlugin::~FlutterInappwebviewWindowsPlugin() - {} + { + if (registrar) { + registrar->UnregisterTopLevelWindowProcDelegate(window_proc_id); + } + webViewEnvironmentManager = nullptr; + inAppWebViewManager = nullptr; + inAppBrowserManager = nullptr; + headlessInAppWebViewManager = nullptr; + cookieManager = nullptr; + platformUtil = nullptr; + } + + + std::optional FlutterInappwebviewWindowsPlugin::HandleWindowProc( + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam) + { + std::optional result = std::nullopt; + + if (platformUtil) { + result = platformUtil->HandleWindowProc(hWnd, message, wParam, lParam); + } + + return result; + } } \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/flutter_inappwebview_windows_plugin.h b/flutter_inappwebview_windows/windows/flutter_inappwebview_windows_plugin.h index 9d0bd4032..b195a5b34 100644 --- a/flutter_inappwebview_windows/windows/flutter_inappwebview_windows_plugin.h +++ b/flutter_inappwebview_windows/windows/flutter_inappwebview_windows_plugin.h @@ -1,7 +1,6 @@ #ifndef FLUTTER_PLUGIN_FLUTTER_INAPPWEBVIEW_PLUGIN_PLUGIN_H_ #define FLUTTER_PLUGIN_FLUTTER_INAPPWEBVIEW_PLUGIN_PLUGIN_H_ -#include #include namespace flutter_inappwebview_plugin @@ -11,6 +10,7 @@ namespace flutter_inappwebview_plugin class InAppBrowserManager; class HeadlessInAppWebViewManager; class CookieManager; + class PlatformUtil; class FlutterInappwebviewWindowsPlugin : public flutter::Plugin { public: @@ -20,6 +20,7 @@ namespace flutter_inappwebview_plugin std::unique_ptr inAppBrowserManager; std::unique_ptr headlessInAppWebViewManager; std::unique_ptr cookieManager; + std::unique_ptr platformUtil; static void RegisterWithRegistrar(flutter::PluginRegistrarWindows* registrar); @@ -30,6 +31,14 @@ namespace flutter_inappwebview_plugin // Disallow copy and assign. FlutterInappwebviewWindowsPlugin(const FlutterInappwebviewWindowsPlugin&) = delete; FlutterInappwebviewWindowsPlugin& operator=(const FlutterInappwebviewWindowsPlugin&) = delete; + private: + // The ID of the WindowProc delegate registration. + int window_proc_id = -1; + std::optional FlutterInappwebviewWindowsPlugin::HandleWindowProc( + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam); }; } #endif // FLUTTER_PLUGIN_FLUTTER_INAPPWEBVIEW_PLUGIN_PLUGIN_H_ diff --git a/flutter_inappwebview_windows/windows/headless_in_app_webview/headless_in_app_webview_manager.cpp b/flutter_inappwebview_windows/windows/headless_in_app_webview/headless_in_app_webview_manager.cpp index e5ff4c447..a74587d59 100644 --- a/flutter_inappwebview_windows/windows/headless_in_app_webview/headless_in_app_webview_manager.cpp +++ b/flutter_inappwebview_windows/windows/headless_in_app_webview/headless_in_app_webview_manager.cpp @@ -46,6 +46,11 @@ namespace flutter_inappwebview_plugin { auto result_ = std::shared_ptr>(std::move(result)); + if (!plugin) { + result_->Error("0", "Cannot create the HeadlessInAppWebView instance!"); + return; + } + auto id = get_fl_map_value(*arguments, "id"); auto params = get_fl_map_value(*arguments, "params"); @@ -80,7 +85,7 @@ namespace flutter_inappwebview_plugin wil::com_ptr webViewController, wil::com_ptr webViewCompositionController) { - if (webViewEnv && webViewController) { + if (plugin && webViewEnv && webViewController) { std::optional>> initialUserScripts = initialUserScriptList.has_value() ? functional_map(initialUserScriptList.value(), [](const flutter::EncodableValue& map) { return std::make_shared(std::get(map)); }) : std::optional>>{}; diff --git a/flutter_inappwebview_windows/windows/headless_in_app_webview/headless_webview_channel_delegate.cpp b/flutter_inappwebview_windows/windows/headless_in_app_webview/headless_webview_channel_delegate.cpp index 5aadab56c..95099be68 100644 --- a/flutter_inappwebview_windows/windows/headless_in_app_webview/headless_webview_channel_delegate.cpp +++ b/flutter_inappwebview_windows/windows/headless_in_app_webview/headless_webview_channel_delegate.cpp @@ -29,6 +29,12 @@ namespace flutter_inappwebview_plugin std::map>& webViews = webView->plugin->headlessInAppWebViewManager->webViews; auto& id = webView->id; if (map_contains(webViews, id)) { + if (webView->channelDelegate) { + webView->channelDelegate->UnregisterMethodCallHandler(); + if (webView->webView && webView->webView->channelDelegate) { + webView->webView->channelDelegate->UnregisterMethodCallHandler(); + } + } webViews.erase(id); } } diff --git a/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser.cpp b/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser.cpp index ec9ad3900..d85f11102 100644 --- a/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser.cpp +++ b/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser.cpp @@ -200,12 +200,18 @@ namespace flutter_inappwebview_plugin if (!destroyed_) { destroyed_ = true; - webView.reset(); - if (channelDelegate) { channelDelegate->onExit(); } + if (channelDelegate) { + channelDelegate->UnregisterMethodCallHandler(); + if (webView && webView->channelDelegate) { + webView->channelDelegate->UnregisterMethodCallHandler(); + } + } + webView.reset(); + if (plugin && plugin->inAppBrowserManager) { plugin->inAppBrowserManager->browsers.erase(id); } diff --git a/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_manager.cpp b/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_manager.cpp index 461300679..7f210f7bb 100644 --- a/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_manager.cpp +++ b/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_manager.cpp @@ -25,8 +25,14 @@ namespace flutter_inappwebview_plugin auto& methodName = method_call.method_name(); if (string_equals(methodName, "open")) { - createInAppBrowser(arguments); - result->Success(true); + if (plugin) { + createInAppBrowser(arguments); + result->Success(true); + } + else { + result->Error("0", "Cannot create the InAppBrowser instance!"); + + } } else if (string_equals(methodName, "openWithSystemBrowser")) { auto url = get_fl_map_value(*arguments, "url"); diff --git a/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_settings.h b/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_settings.h index 1243ca2b9..d5be8ee56 100644 --- a/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_settings.h +++ b/flutter_inappwebview_windows/windows/in_app_browser/in_app_browser_settings.h @@ -11,7 +11,7 @@ namespace flutter_inappwebview_plugin { class InAppBrowser; - enum InAppBrowserWindowType { + enum class InAppBrowserWindowType { window, child }; @@ -20,7 +20,7 @@ namespace flutter_inappwebview_plugin { public: bool hidden = false; - InAppBrowserWindowType windowType = window; + InAppBrowserWindowType windowType = InAppBrowserWindowType::window; std::string toolbarTopFixedTitle; double windowAlphaValue = 1.0; std::shared_ptr windowFrame; diff --git a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.cpp b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.cpp index f222a7ac9..950d245c9 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.cpp +++ b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.cpp @@ -1,12 +1,20 @@ #include #include #include +#include #include #include +#include #include "../custom_platform_view/util/composition.desktop.interop.h" #include "../plugin_scripts_js/javascript_bridge_js.h" +#include "../types/client_cert_response.h" #include "../types/create_window_action.h" +#include "../types/http_auth_response.h" +#include "../types/javascript_handler_function_data.h" +#include "../types/server_trust_auth_response.h" +#include "../types/ssl_error.h" +#include "../types/url_credential.h" #include "../types/web_resource_error.h" #include "../types/web_resource_request.h" #include "../utils/base64.h" @@ -14,7 +22,7 @@ #include "../utils/map.h" #include "../utils/strconv.h" #include "../utils/string.h" -#include "../webview_environment/webview_environment_manager.h" +#include "../utils/uri.h" #include "in_app_webview.h" #include "in_app_webview_manager.h" @@ -189,6 +197,8 @@ namespace flutter_inappwebview_plugin return; } + javaScriptBridgeEnabled = settings->javaScriptBridgeEnabled; + wil::com_ptr webView2Settings; auto hrWebView2Settings = webView->get_Settings(&webView2Settings); if (succeededOrLog(hrWebView2Settings)) { @@ -196,18 +206,47 @@ namespace flutter_inappwebview_plugin webView2Settings->put_IsZoomControlEnabled(settings->supportZoom); webView2Settings->put_AreDevToolsEnabled(settings->isInspectable); webView2Settings->put_AreDefaultContextMenusEnabled(!settings->disableContextMenu); + webView2Settings->put_IsBuiltInErrorPageEnabled(!settings->disableDefaultErrorPage); + webView2Settings->put_IsStatusBarEnabled(settings->statusBarEnabled); - wil::com_ptr webView2Settings2; - if (succeededOrLog(webView2Settings->QueryInterface(IID_PPV_ARGS(&webView2Settings2)))) { + if (auto webView2Settings2 = webView2Settings.try_query()) { if (!settings->userAgent.empty()) { webView2Settings2->put_UserAgent(utf8_to_wide(settings->userAgent).c_str()); } } + + if (auto webView2Settings3 = webView2Settings.try_query()) { + webView2Settings3->put_AreBrowserAcceleratorKeysEnabled(settings->browserAcceleratorKeysEnabled); + } + + if (auto webView2Settings4 = webView2Settings.try_query()) { + webView2Settings4->put_IsGeneralAutofillEnabled(settings->generalAutofillEnabled); + webView2Settings4->put_IsPasswordAutosaveEnabled(settings->passwordAutosaveEnabled); + } + + if (auto webView2Settings5 = webView2Settings.try_query()) { + webView2Settings5->put_IsPinchZoomEnabled(settings->pinchZoomEnabled); + } + + if (auto webView2Settings6 = webView2Settings.try_query()) { + webView2Settings6->put_IsSwipeNavigationEnabled(settings->allowsBackForwardNavigationGestures); + } + + if (auto webView2Settings7 = webView2Settings.try_query()) { + webView2Settings7->put_HiddenPdfToolbarItems((COREWEBVIEW2_PDF_TOOLBAR_ITEMS)settings->hiddenPdfToolbarItems); + } + + if (auto webView2Settings8 = webView2Settings.try_query()) { + webView2Settings8->put_IsReputationCheckingRequired(settings->reputationCheckingRequired); + } + + if (auto webView2Settings9 = webView2Settings.try_query()) { + webView2Settings9->put_IsNonClientRegionSupportEnabled(settings->nonClientRegionSupportEnabled); + } } - wil::com_ptr webViewController2; - if (succeededOrLog(webViewController->QueryInterface(IID_PPV_ARGS(&webViewController2)))) { - if (!settings->transparentBackground) { + if (auto webViewController2 = webViewController.try_query()) { + if (settings->transparentBackground) { webViewController2->put_DefaultBackgroundColor({ 0, 255, 255, 255 }); } } @@ -260,7 +299,15 @@ namespace flutter_inappwebview_plugin ).Get())); if (userContentController) { - userContentController->addPluginScript(std::move(createJavaScriptBridgePluginScript())); + if (javaScriptBridgeEnabled) { + auto pluginScriptsOriginAllowList = settings->pluginScriptsOriginAllowList; + auto pluginScriptsForMainFrameOnly = settings->pluginScriptsForMainFrameOnly; + + auto javaScriptBridgeOriginAllowList = settings->javaScriptBridgeOriginAllowList.has_value() ? settings->javaScriptBridgeOriginAllowList : pluginScriptsOriginAllowList; + auto javaScriptBridgeForMainFrameOnly = settings->javaScriptBridgeForMainFrameOnly.has_value() ? settings->javaScriptBridgeForMainFrameOnly.value() : pluginScriptsForMainFrameOnly; + userContentController->addPluginScript(std::move(JavaScriptBridgeJS::JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT(expectedBridgeSecret, javaScriptBridgeOriginAllowList, javaScriptBridgeForMainFrameOnly))); + } + if (params.initialUserScripts.has_value()) { userContentController->addUserOnlyScripts(params.initialUserScripts.value()); } @@ -271,14 +318,46 @@ namespace flutter_inappwebview_plugin void InAppWebView::registerEventHandlers() { - if (!webView) { + if (!webView || !webViewController) { return; } - wil::com_ptr fetchRequestPausedEventReceiver; + auto add_AcceleratorKeyPressed_HResult = webViewController->add_AcceleratorKeyPressed( + Callback( + [this](ICoreWebView2Controller* sender, ICoreWebView2AcceleratorKeyPressedEventArgs* args) + { + if (channelDelegate) { + auto handled = settings->handleAcceleratorKeyPressed; + args->put_Handled(handled); + if (handled) { + auto detail = AcceleratorKeyPressedDetail::fromICoreWebView2AcceleratorKeyPressedEventArgs(args); + channelDelegate->onAcceleratorKeyPressed(std::move(detail)); + } + } + return S_OK; + } + ).Get(), nullptr); + failedLog(add_AcceleratorKeyPressed_HResult); + + auto add_ZoomFactorChanged_HResult = webViewController->add_ZoomFactorChanged( + Callback( + [this](ICoreWebView2Controller* sender, IUnknown* args) + { + double newScale; + if (succeededOrLog(sender->get_ZoomFactor(&newScale))) { + if (channelDelegate) { + channelDelegate->onZoomScaleChanged(zoomScaleFactor_, newScale); + } + zoomScaleFactor_ = newScale; + } + return S_OK; + } + ).Get(), nullptr); + failedLog(add_ZoomFactorChanged_HResult); + wil::com_ptr fetchRequestPausedEventReceiver; if (succeededOrLog(webView->GetDevToolsProtocolEventReceiver(L"Fetch.requestPaused", &fetchRequestPausedEventReceiver))) { - failedAndLog(fetchRequestPausedEventReceiver->add_DevToolsProtocolEventReceived( + auto add_DevToolsProtocolEventReceived_HResult = fetchRequestPausedEventReceiver->add_DevToolsProtocolEventReceived( Callback( [this]( ICoreWebView2* sender, @@ -412,10 +491,11 @@ namespace flutter_inappwebview_plugin return S_OK; }) - .Get(), nullptr)); + .Get(), nullptr); + failedAndLog(add_DevToolsProtocolEventReceived_HResult); } - failedLog(webView->add_NavigationStarting( + auto add_NavigationStarting_HResult = webView->add_NavigationStarting( Callback( [this](ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args) { @@ -515,9 +595,10 @@ namespace flutter_inappwebview_plugin return S_OK; } - ).Get(), nullptr)); + ).Get(), nullptr); + failedLog(add_NavigationStarting_HResult); - failedLog(webView->add_ContentLoading( + auto add_ContentLoading_HResult = webView->add_ContentLoading( Callback( [this](ICoreWebView2* sender, ICoreWebView2ContentLoadingEventArgs* args) { @@ -526,15 +607,17 @@ namespace flutter_inappwebview_plugin } return S_OK; } - ).Get(), nullptr)); + ).Get(), nullptr); + failedLog(add_ContentLoading_HResult); - failedLog(webView->add_NavigationCompleted( + auto add_NavigationCompleted_HResult = webView->add_NavigationCompleted( Callback( [this](ICoreWebView2* sender, ICoreWebView2NavigationCompletedEventArgs* args) { isLoading_ = false; + previousAuthRequestFailureCount = 0; - evaluateJavascript(PLATFORM_READY_JS_SOURCE, ContentWorld::page(), nullptr); + evaluateJavascript(JavaScriptBridgeJS::PLATFORM_READY_JS_SOURCE(), ContentWorld::page(), nullptr); std::shared_ptr navigationAction; UINT64 navigationId; @@ -581,9 +664,10 @@ namespace flutter_inappwebview_plugin return S_OK; } - ).Get(), nullptr)); + ).Get(), nullptr); + failedLog(add_NavigationCompleted_HResult); - failedLog(webView->add_DocumentTitleChanged(Callback( + auto add_DocumentTitleChanged_HResult = webView->add_DocumentTitleChanged(Callback( [this](ICoreWebView2* sender, IUnknown* args) { if (channelDelegate) { @@ -593,9 +677,10 @@ namespace flutter_inappwebview_plugin } return S_OK; } - ).Get(), nullptr)); + ).Get(), nullptr); + failedLog(add_DocumentTitleChanged_HResult); - failedLog(webView->add_HistoryChanged(Callback( + auto add_HistoryChanged_HResult = webView->add_HistoryChanged(Callback( [this](ICoreWebView2* sender, IUnknown* args) { if (channelDelegate) { @@ -607,63 +692,20 @@ namespace flutter_inappwebview_plugin } return S_OK; } - ).Get(), nullptr)); + ).Get(), nullptr); + failedLog(add_HistoryChanged_HResult); - failedLog(webView->add_WebMessageReceived(Callback( + auto add_WebMessageReceived_HResult = webView->add_WebMessageReceived(Callback( [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) { - if (!channelDelegate) { - return S_OK; - } - - wil::unique_cotaskmem_string json; - if (succeededOrLog(args->get_WebMessageAsJson(&json))) { - auto message = nlohmann::json::parse(wide_to_utf8(json.get())); - - if (message.is_object() && message.contains("name") && message.at("name").is_string() && message.contains("body") && message.at("body").is_object()) { - auto name = message.at("name").get(); - auto body = message.at("body").get(); - - if (name.compare("callHandler") == 0 && body.contains("handlerName") && body.at("handlerName").is_string()) { - auto handlerName = body.at("handlerName").get(); - auto callHandlerID = body.at("_callHandlerID").is_number_integer() ? body.at("_callHandlerID").get() : 0; - std::string handlerArgs = body.at("args").is_string() ? body.at("args").get() : ""; - - auto callback = std::make_unique(); - callback->defaultBehaviour = [this, callHandlerID](const std::optional response) - { - std::string json = "null"; - if (response.has_value() && !response.value()->IsNull()) { - json = std::get(*(response.value())); - } - - evaluateJavascript("if (window." + JAVASCRIPT_BRIDGE_NAME + "[" + std::to_string(callHandlerID) + "] != null) { \ - window." + JAVASCRIPT_BRIDGE_NAME + "[" + std::to_string(callHandlerID) + "].resolve(" + json + "); \ - delete window." + JAVASCRIPT_BRIDGE_NAME + "[" + std::to_string(callHandlerID) + "]; \ - }", ContentWorld::page(), nullptr); - }; - callback->error = [this, callHandlerID](const std::string& error_code, const std::string& error_message, const flutter::EncodableValue* error_details) - { - auto errorMessage = error_code + ", " + error_message; - debugLog(errorMessage); - - evaluateJavascript("if (window." + JAVASCRIPT_BRIDGE_NAME + "[" + std::to_string(callHandlerID) + "] != null) { \ - window." + JAVASCRIPT_BRIDGE_NAME + "[" + std::to_string(callHandlerID) + "].reject(new Error('" + replace_all_copy(errorMessage, "\'", "\\'") + "')); \ - delete window." + JAVASCRIPT_BRIDGE_NAME + "[" + std::to_string(callHandlerID) + "]; \ - }", ContentWorld::page(), nullptr); - }; - channelDelegate->onCallJsHandler(handlerName, handlerArgs, std::move(callback)); - } - } - } - - return S_OK; + return this->onCallJsHandler(true, args); } - ).Get(), nullptr)); + ).Get(), nullptr); + failedLog(add_WebMessageReceived_HResult); wil::com_ptr consoleMessageReceiver; if (succeededOrLog(webView->GetDevToolsProtocolEventReceiver(L"Runtime.consoleAPICalled", &consoleMessageReceiver))) { - failedLog(consoleMessageReceiver->add_DevToolsProtocolEventReceived( + auto consoleMessageReceiver_add_DevToolsProtocolEventReceived_HResult = consoleMessageReceiver->add_DevToolsProtocolEventReceived( Callback( [this]( ICoreWebView2* sender, @@ -703,10 +745,11 @@ namespace flutter_inappwebview_plugin return S_OK; }) - .Get(), nullptr)); + .Get(), nullptr); + failedLog(consoleMessageReceiver_add_DevToolsProtocolEventReceived_HResult); } - failedLog(webView->add_NewWindowRequested( + auto add_NewWindowRequested_HResult = webView->add_NewWindowRequested( Callback( [this](ICoreWebView2* sender, ICoreWebView2NewWindowRequestedEventArgs* args) { @@ -763,9 +806,10 @@ namespace flutter_inappwebview_plugin } return S_OK; } - ).Get(), nullptr)); + ).Get(), nullptr); + failedLog(add_NewWindowRequested_HResult); - failedLog(webView->add_WindowCloseRequested(Callback( + auto add_WindowCloseRequested_HResult = webView->add_WindowCloseRequested(Callback( [this](ICoreWebView2* sender, IUnknown* args) { if (channelDelegate) { @@ -773,9 +817,10 @@ namespace flutter_inappwebview_plugin } return S_OK; } - ).Get(), nullptr)); + ).Get(), nullptr); + failedLog(add_WindowCloseRequested_HResult); - failedLog(webView->add_PermissionRequested(Callback( + auto add_PermissionRequested_HResult = webView->add_PermissionRequested(Callback( [this](ICoreWebView2* sender, ICoreWebView2PermissionRequestedEventArgs* args) { wil::com_ptr deferral; @@ -784,7 +829,7 @@ namespace flutter_inappwebview_plugin std::string url = SUCCEEDED(args->get_Uri(&uri)) ? wide_to_utf8(uri.get()) : ""; COREWEBVIEW2_PERMISSION_KIND resource = COREWEBVIEW2_PERMISSION_KIND_UNKNOWN_PERMISSION; - failedAndLog(args->get_PermissionKind(&resource)); + failedLog(args->get_PermissionKind(&resource)); auto callback = std::make_unique(); auto defaultBehaviour = [this, deferral, args](const std::optional> permissionResponse) @@ -822,10 +867,11 @@ namespace flutter_inappwebview_plugin } return S_OK; } - ).Get(), nullptr)); + ).Get(), nullptr); + failedLog(add_PermissionRequested_HResult); failedLog(webView->AddWebResourceRequestedFilter(L"*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL)); - failedLog(webView->add_WebResourceRequested( + auto add_WebResourceRequested_HResult = webView->add_WebResourceRequested( Callback( [this]( ICoreWebView2* sender, ICoreWebView2WebResourceRequestedEventArgs* args) @@ -907,11 +953,80 @@ namespace flutter_inappwebview_plugin } return S_OK; } - ).Get(), nullptr)); + ).Get(), nullptr); + failedLog(add_WebResourceRequested_HResult); + + auto add_ProcessFailed_HResult = webView->add_ProcessFailed( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2ProcessFailedEventArgs* argsRaw) + { + if (!channelDelegate) { + return S_OK; + } + + wil::com_ptr args = argsRaw; + auto args2 = args.try_query(); + auto args3 = args.try_query(); + + COREWEBVIEW2_PROCESS_FAILED_REASON reason = COREWEBVIEW2_PROCESS_FAILED_REASON_UNEXPECTED; + if (args2) { + args2->get_Reason(&reason); + } + + COREWEBVIEW2_PROCESS_FAILED_KIND kind; + if (succeededOrLog(args->get_ProcessFailedKind(&kind))) { + if (kind == COREWEBVIEW2_PROCESS_FAILED_KIND_BROWSER_PROCESS_EXITED) { + auto didCrash = reason == COREWEBVIEW2_PROCESS_FAILED_REASON_CRASHED; + auto detail = std::make_unique( + didCrash + ); + channelDelegate->onRenderProcessGone(std::move(detail)); + } + else if (kind == COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_UNRESPONSIVE) { + channelDelegate->onRenderProcessUnresponsive(getUrl()); + } + else if (kind == COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_EXITED) { + channelDelegate->onWebContentProcessDidTerminate(); + } + + auto frameInfos = std::optional>>{}; + wil::com_ptr frameInfoCollection; + wil::com_ptr frameIterator; + if (args2 && succeededOrLog(args2->get_FrameInfosForFailedProcess(&frameInfoCollection)) && frameInfoCollection && succeededOrLog(frameInfoCollection->GetIterator(&frameIterator))) { + frameInfos = std::vector>{}; + BOOL hasCurrent = FALSE; + while (SUCCEEDED(frameIterator->MoveNext(&hasCurrent)) && hasCurrent) { + wil::com_ptr frameInfo; + if (SUCCEEDED(frameIterator->GetCurrent(&frameInfo))) { + frameInfos.value().push_back(std::move(FrameInfo::fromICoreWebView2FrameInfo(frameInfo))); + } + BOOL hasNext = FALSE; + failedLog(frameIterator->MoveNext(&hasNext)); + } + } + + wil::unique_cotaskmem_string processDescription; + int exitCode; + wil::unique_cotaskmem_string failedModule; + + auto detail = std::make_unique( + (int64_t)kind, + args2 && succeededOrLog(args2->get_ExitCode(&exitCode)) ? exitCode : std::optional{}, + args2 && succeededOrLog(args2->get_ProcessDescription(&processDescription)) ? wide_to_utf8(processDescription.get()) : std::optional{}, + args2 ? (int64_t)reason : std::optional{}, + args3 && succeededOrLog(args3->get_FailureSourceModulePath(&failedModule)) ? wide_to_utf8(failedModule.get()) : std::optional{}, + frameInfos + ); + channelDelegate->onProcessFailed(std::move(detail)); + } + return S_OK; + } + ).Get(), nullptr); + failedLog(add_ProcessFailed_HResult); wil::com_ptr webView2; if (SUCCEEDED(webView->QueryInterface(IID_PPV_ARGS(&webView2)))) { - failedLog(webView2->add_DOMContentLoaded( + auto add_DOMContentLoaded_HResult = webView2->add_DOMContentLoaded( Callback( [this](ICoreWebView2* sender, ICoreWebView2DOMContentLoadedEventArgs* args) { @@ -920,27 +1035,389 @@ namespace flutter_inappwebview_plugin } return S_OK; } - ).Get(), nullptr)); + ).Get(), nullptr); + failedLog(add_DOMContentLoaded_HResult); + } + + wil::com_ptr webView4; + if (SUCCEEDED(webView->QueryInterface(IID_PPV_ARGS(&webView4)))) { + auto add_FrameCreated_HResult = webView4->add_FrameCreated( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args) + { + wil::com_ptr frame; + wil::com_ptr frame2; + if (succeededOrLog(args->get_Frame(&frame)) && SUCCEEDED(frame->QueryInterface(IID_PPV_ARGS(&frame2)))) { + auto frame_add_WebMessageReceived_HResult = frame2->add_WebMessageReceived(Callback( + [this](ICoreWebView2Frame* sender, ICoreWebView2WebMessageReceivedEventArgs* args) + { + return this->onCallJsHandler(false, args); + }).Get(), nullptr); + failedLog(frame_add_WebMessageReceived_HResult); + } + return S_OK; + } + ).Get(), nullptr); + failedLog(add_FrameCreated_HResult); + + auto add_DownloadStarting_HResult = webView4->add_DownloadStarting( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2DownloadStartingEventArgs* args) + { + wil::com_ptr deferral; + wil::com_ptr download; + if (channelDelegate && settings->useOnDownloadStart && succeededOrLog(args->get_DownloadOperation(&download)) && succeededOrLog(args->GetDeferral(&deferral))) { + + wil::unique_cotaskmem_string uri; + std::string url = SUCCEEDED(download->get_Uri(&uri)) ? wide_to_utf8(uri.get()) : ""; + + INT64 contentLength = 0; + failedLog(download->get_TotalBytesToReceive(&contentLength)); + + wil::unique_cotaskmem_string downloadMimeType; + std::optional mimeType = SUCCEEDED(download->get_MimeType(&downloadMimeType)) ? wide_to_utf8(downloadMimeType.get()) : std::optional{}; + + wil::unique_cotaskmem_string downloadContentDisposition; + std::optional contentDisposition = SUCCEEDED(download->get_ContentDisposition(&downloadContentDisposition)) ? wide_to_utf8(downloadContentDisposition.get()) : std::optional{}; + + wil::unique_cotaskmem_string resultFilePath; + std::optional suggestedFilename = SUCCEEDED(download->get_ContentDisposition(&resultFilePath)) ? wide_to_utf8(resultFilePath.get()) : std::optional{}; + + auto request = std::make_shared( + contentDisposition, + contentLength, + mimeType, + suggestedFilename, + url + ); + + auto callback = std::make_unique(); + auto defaultBehaviour = [this, deferral, args](const std::optional> response) + { + failedLog(deferral->Complete()); + }; + callback->nonNullSuccess = [this, deferral, args](const std::shared_ptr response) + { + failedLog(args->put_Handled(response->handled)); + auto resultFilePath = response->resultFilePath; + if (resultFilePath.has_value()) { + failedLog(args->put_ResultFilePath(utf8_to_wide(resultFilePath.value()).c_str())); + } + auto action = response->action; + if (action.has_value()) { + switch (action.value()) { + case DownloadStartResponseAction::cancel: + failedLog(args->put_Cancel(true)); + break; + } + } + failedLog(deferral->Complete()); + return false; + }; + callback->defaultBehaviour = defaultBehaviour; + callback->error = [this, defaultBehaviour](const std::string& error_code, const std::string& error_message, const flutter::EncodableValue* error_details) + { + debugLog(error_code + ", " + error_message); + defaultBehaviour(std::nullopt); + }; + channelDelegate->onDownloadStarting(std::move(request), std::move(callback)); + } + return S_OK; + } + ).Get(), nullptr); + failedLog(add_DownloadStarting_HResult); + } + + if (auto webView5 = webView.try_query()) { + auto add_ClientCertificateRequested_HResult = webView5->add_ClientCertificateRequested( + Callback( + [this]( + ICoreWebView2* sender, + ICoreWebView2ClientCertificateRequestedEventArgs* args) + { + wil::com_ptr deferral; + wil::unique_cotaskmem_string host; + + if (channelDelegate && plugin && plugin->inAppWebViewManager && + succeededOrLog(args->get_Host(&host)) && succeededOrLog(args->GetDeferral(&deferral))) { + + std::vector> mutuallyTrustedCertificates = {}; + wil::com_ptr certificateCollection; + uint32_t certCount = 0; + if (succeededOrLog(args->get_MutuallyTrustedCertificates(&certificateCollection)) && succeededOrLog(certificateCollection->get_Count(&certCount))) { + + for (uint32_t i = 0; i < certCount; i++) { + wil::com_ptr clientCert; + if (succeededOrLog(certificateCollection->GetValueAtIndex(i, &clientCert))) { + wil::unique_cotaskmem_string certPemEncoded; + if (succeededOrLog(clientCert->ToPemEncoding(&certPemEncoded))) { + mutuallyTrustedCertificates.push_back(std::make_shared(wide_to_utf8(certPemEncoded.get()))); + } + } + } + } + + std::vector allowedCertificateAuthorities = {}; + wil::com_ptr authoritiesCollection; + uint32_t authoritiesCount = 0; + if (succeededOrLog(args->get_AllowedCertificateAuthorities(&authoritiesCollection)) && succeededOrLog(authoritiesCollection->get_Count(&authoritiesCount))) { + for (uint32_t i = 0; i < authoritiesCount; i++) { + wil::unique_cotaskmem_string authority; + if (succeededOrLog(authoritiesCollection->GetValueAtIndex(i, &authority))) { + allowedCertificateAuthorities.push_back(base64_decode(wide_to_utf8(authority.get()))); + } + } + } + + args->get_AllowedCertificateAuthorities(&authoritiesCollection); + + int port = 0; + args->get_Port(&port); + + BOOL isProxy = false; + args->get_IsProxy(&isProxy); + + std::string scheme = ""; + auto currentUrl = getUrl(); + if (currentUrl.has_value()) { + scheme = currentUrl.value().substr(0, currentUrl.value().find(':')); + } + + auto protectionSpace = std::make_unique( + wide_to_utf8(host.get()), + scheme, + std::optional{}, + port, + std::optional>{}, + std::optional>{} + ); + auto challenge = std::make_unique( + std::move(protectionSpace), + allowedCertificateAuthorities, + isProxy, + mutuallyTrustedCertificates + ); + + auto callback = std::make_unique(); + auto defaultBehaviour = [this, deferral, args](const std::optional> response) + { + failedLog(deferral->Complete()); + }; + callback->nonNullSuccess = [this, deferral, certCount, certificateCollection, args](const std::shared_ptr response) + { + auto action = response->action; + + if (action.has_value()) { + switch (action.value()) { + case ClientCertResponseAction::proceed: + if (certCount > 0 && response->selectedCertificate >= 0) { + wil::com_ptr selectedClientCert; + if (succeededOrLog(certificateCollection->GetValueAtIndex((uint32_t)response->selectedCertificate, &selectedClientCert))) { + args->put_SelectedCertificate(selectedClientCert.get()); + } + } + args->put_Handled(true); + args->put_Cancel(false); + break; + case ClientCertResponseAction::ignore: + args->put_Handled(true); + args->put_Cancel(false); + break; + case ClientCertResponseAction::cancel: + default: + args->put_Cancel(true); + break; + } + failedLog(deferral->Complete()); + return false; + } + return true; + }; + callback->defaultBehaviour = defaultBehaviour; + callback->error = [this, defaultBehaviour](const std::string& error_code, const std::string& error_message, const flutter::EncodableValue* error_details) + { + debugLog(error_code + ", " + error_message); + defaultBehaviour(std::nullopt); + }; + channelDelegate->onReceivedClientCertRequest(std::move(challenge), std::move(callback)); + } + return S_OK; + }) + .Get(), nullptr); + failedLog(add_ClientCertificateRequested_HResult); } - /* - wil::com_ptr webView14; - if (SUCCEEDED(webView->QueryInterface(IID_PPV_ARGS(&webView14)))) { - failedLog(webView14->add_ServerCertificateErrorDetected( + if (auto webView10 = webView.try_query()) { + auto add_BasicAuthenticationRequested_HResult = webView10->add_BasicAuthenticationRequested( + Callback( + [this]( + ICoreWebView2* sender, + ICoreWebView2BasicAuthenticationRequestedEventArgs* args) + { + wil::com_ptr deferral; + wil::com_ptr basicAuthenticationResponse; + wil::unique_cotaskmem_string url; + wil::unique_cotaskmem_string realmChallenge; + + if (channelDelegate && plugin && plugin->inAppWebViewManager && + succeededOrLog(args->get_Uri(&url)) && succeededOrLog(args->get_Challenge(&realmChallenge)) && + succeededOrLog(args->get_Response(&basicAuthenticationResponse)) && succeededOrLog(args->GetDeferral(&deferral))) { + + previousAuthRequestFailureCount++; + + try { + winrt::Windows::Foundation::Uri const uri{ url.get() }; + + auto basicRealm = std::string{ "Basic realm=\"" }; + auto basicRealmLength = basicRealm.length(); + auto realm = wide_to_utf8(realmChallenge.get()); + if (starts_with(realm, basicRealm)) { + realm = realm.substr(basicRealmLength, realm.length() - basicRealmLength - 1); + } + + auto protectionSpace = std::make_unique( + wide_to_utf8(uri.Host().c_str()), + wide_to_utf8(uri.SchemeName().c_str()), + realm, + uri.Port(), + std::optional>{}, + std::optional>{} + ); + auto challenge = std::make_unique( + std::move(protectionSpace), + previousAuthRequestFailureCount, + std::optional>{} + ); + + auto callback = std::make_unique(); + auto defaultBehaviour = [this, deferral, args](const std::optional> response) + { + failedLog(deferral->Complete()); + }; + callback->nonNullSuccess = [this, deferral, basicAuthenticationResponse, args](const std::shared_ptr response) + { + auto action = response->action; + std::wstring username = utf8_to_wide(response->username); + std::wstring password = utf8_to_wide(response->password); + + if (action.has_value()) { + switch (action.value()) { + case HttpAuthResponseAction::proceed: + failedLog(basicAuthenticationResponse->put_UserName(username.c_str())); + failedLog(basicAuthenticationResponse->put_Password(password.c_str())); + break; + case HttpAuthResponseAction::cancel: + default: + args->put_Cancel(true); + break; + } + failedLog(deferral->Complete()); + return false; + } + return true; + }; + callback->defaultBehaviour = defaultBehaviour; + callback->error = [this, defaultBehaviour](const std::string& error_code, const std::string& error_message, const flutter::EncodableValue* error_details) + { + debugLog(error_code + ", " + error_message); + defaultBehaviour(std::nullopt); + }; + channelDelegate->onReceivedHttpAuthRequest(std::move(challenge), std::move(callback)); + } + catch (winrt::hresult_error const& ex) { + debugLog(wide_to_utf8(ex.message().c_str())); + } + } + return S_OK; + }) + .Get(), nullptr); + failedLog(add_BasicAuthenticationRequested_HResult); + } + + if (auto webView14 = webView.try_query()) { + auto add_ServerCertificateErrorDetected_HResult = webView14->add_ServerCertificateErrorDetected( Callback( [this](ICoreWebView2* sender, ICoreWebView2ServerCertificateErrorDetectedEventArgs* args) { - debugLog("add_ServerCertificateErrorDetected"); - wil::com_ptr certificate = nullptr; - if (SUCCEEDED(args->get_ServerCertificate(&certificate))) { - wil::unique_cotaskmem_string displayName = nullptr; - std::optional url = SUCCEEDED(certificate->get_DisplayName(&displayName)) ? wide_to_utf8(displayName.get()) : std::optional{}; - debugLog(displayName.get()); + wil::com_ptr deferral; + wil::unique_cotaskmem_string requestUrl; + if (succeededOrLog(args->get_RequestUri(&requestUrl)) && succeededOrLog(args->GetDeferral(&deferral))) { + + wil::com_ptr serverCert; + auto sslCert = std::optional>{}; + if (succeededOrLog(args->get_ServerCertificate(&serverCert))) { + wil::unique_cotaskmem_string certPemEncoded; + if (succeededOrLog(serverCert->ToPemEncoding(&certPemEncoded))) { + sslCert = std::make_shared(wide_to_utf8(certPemEncoded.get())); + } + } + + auto sslError = std::optional>{}; + COREWEBVIEW2_WEB_ERROR_STATUS errorStatus; + if (succeededOrLog(args->get_ErrorStatus(&errorStatus))) { + sslError = std::make_shared( + errorStatus, + COREWEBVIEW2_WEB_ERROR_STATUS_ToString(errorStatus) + ); + } + + try { + winrt::Windows::Foundation::Uri const uri{ requestUrl.get() }; + + auto protectionSpace = std::make_unique( + wide_to_utf8(uri.Host().c_str()), + wide_to_utf8(uri.SchemeName().c_str()), + std::optional{}, + uri.Port(), + sslCert, + sslError + ); + auto challenge = std::make_unique( + std::move(protectionSpace) + ); + + auto callback = std::make_unique(); + auto defaultBehaviour = [this, deferral, args](const std::optional> response) + { + failedLog(deferral->Complete()); + }; + callback->nonNullSuccess = [this, deferral, args](const std::shared_ptr response) + { + auto action = response->action; + + if (action.has_value()) { + switch (action.value()) { + case ServerTrustAuthResponseAction::proceed: + args->put_Action(COREWEBVIEW2_SERVER_CERTIFICATE_ERROR_ACTION_ALWAYS_ALLOW); + break; + case ServerTrustAuthResponseAction::cancel: + args->put_Action(COREWEBVIEW2_SERVER_CERTIFICATE_ERROR_ACTION_CANCEL); + break; + default: + args->put_Action(COREWEBVIEW2_SERVER_CERTIFICATE_ERROR_ACTION_DEFAULT); + } + failedLog(deferral->Complete()); + return false; + } + return true; + }; + callback->defaultBehaviour = defaultBehaviour; + callback->error = [this, defaultBehaviour](const std::string& error_code, const std::string& error_message, const flutter::EncodableValue* error_details) + { + debugLog(error_code + ", " + error_message); + defaultBehaviour(std::nullopt); + }; + channelDelegate->onReceivedServerTrustAuthRequest(std::move(challenge), std::move(callback)); + } + catch (winrt::hresult_error const& ex) { + debugLog(wide_to_utf8(ex.message().c_str())); + } } return S_OK; } - ).Get(), nullptr)); - }*/ + ).Get(), nullptr); + failedLog(add_ServerCertificateErrorDetected_HResult); + } if (userContentController) { userContentController->registerEventHandlers(); @@ -1430,16 +1907,67 @@ namespace flutter_inappwebview_plugin webView2Settings->put_AreDefaultContextMenusEnabled(!newSettings->disableContextMenu); } - wil::com_ptr webView2Settings2; - if (succeededOrLog(webView2Settings->QueryInterface(IID_PPV_ARGS(&webView2Settings2)))) { + if (fl_map_contains_not_null(newSettingsMap, "disableDefaultErrorPage") && settings->disableDefaultErrorPage != newSettings->disableDefaultErrorPage) { + webView2Settings->put_IsBuiltInErrorPageEnabled(!newSettings->disableDefaultErrorPage); + } + + if (fl_map_contains_not_null(newSettingsMap, "statusBarEnabled") && settings->statusBarEnabled != newSettings->statusBarEnabled) { + webView2Settings->put_IsStatusBarEnabled(newSettings->statusBarEnabled); + } + + if (auto webView2Settings2 = webView2Settings.try_query()) { if (fl_map_contains_not_null(newSettingsMap, "userAgent") && !string_equals(settings->userAgent, newSettings->userAgent)) { webView2Settings2->put_UserAgent(utf8_to_wide(newSettings->userAgent).c_str()); } } + + if (auto webView2Settings3 = webView2Settings.try_query()) { + if (fl_map_contains_not_null(newSettingsMap, "browserAcceleratorKeysEnabled") && settings->browserAcceleratorKeysEnabled != newSettings->browserAcceleratorKeysEnabled) { + webView2Settings3->put_AreBrowserAcceleratorKeysEnabled(newSettings->browserAcceleratorKeysEnabled); + } + } + + if (auto webView2Settings4 = webView2Settings.try_query()) { + if (fl_map_contains_not_null(newSettingsMap, "generalAutofillEnabled") && settings->generalAutofillEnabled != newSettings->generalAutofillEnabled) { + webView2Settings4->put_IsGeneralAutofillEnabled(newSettings->generalAutofillEnabled); + } + if (fl_map_contains_not_null(newSettingsMap, "passwordAutosaveEnabled") && settings->passwordAutosaveEnabled != newSettings->passwordAutosaveEnabled) { + webView2Settings4->put_IsPasswordAutosaveEnabled(newSettings->passwordAutosaveEnabled); + } + } + + if (auto webView2Settings5 = webView2Settings.try_query()) { + if (fl_map_contains_not_null(newSettingsMap, "pinchZoomEnabled") && settings->pinchZoomEnabled != newSettings->pinchZoomEnabled) { + webView2Settings5->put_IsPinchZoomEnabled(newSettings->pinchZoomEnabled); + } + } + + if (auto webView2Settings6 = webView2Settings.try_query()) { + if (fl_map_contains_not_null(newSettingsMap, "allowsBackForwardNavigationGestures") && settings->allowsBackForwardNavigationGestures != newSettings->allowsBackForwardNavigationGestures) { + webView2Settings6->put_IsSwipeNavigationEnabled(newSettings->allowsBackForwardNavigationGestures); + } + } + + if (auto webView2Settings7 = webView2Settings.try_query()) { + if (fl_map_contains_not_null(newSettingsMap, "hiddenPdfToolbarItems") && settings->hiddenPdfToolbarItems != newSettings->hiddenPdfToolbarItems) { + webView2Settings7->put_HiddenPdfToolbarItems((COREWEBVIEW2_PDF_TOOLBAR_ITEMS)newSettings->hiddenPdfToolbarItems); + } + } + + if (auto webView2Settings8 = webView2Settings.try_query()) { + if (fl_map_contains_not_null(newSettingsMap, "reputationCheckingRequired") && settings->reputationCheckingRequired != newSettings->reputationCheckingRequired) { + webView2Settings8->put_IsReputationCheckingRequired(newSettings->reputationCheckingRequired); + } + } + + if (auto webView2Settings9 = webView2Settings.try_query()) { + if (fl_map_contains_not_null(newSettingsMap, "nonClientRegionSupportEnabled") && settings->nonClientRegionSupportEnabled != newSettings->nonClientRegionSupportEnabled) { + webView2Settings9->put_IsNonClientRegionSupportEnabled(newSettings->nonClientRegionSupportEnabled); + } + } } - wil::com_ptr webViewController2; - if (succeededOrLog(webViewController->QueryInterface(IID_PPV_ARGS(&webViewController2)))) { + if (auto webViewController2 = webViewController.try_query()) { if (fl_map_contains_not_null(newSettingsMap, "transparentBackground") && settings->transparentBackground != newSettings->transparentBackground) { BYTE alpha = newSettings->transparentBackground ? 0 : 255; webViewController2->put_DefaultBackgroundColor({ alpha, 255, 255, 255 }); @@ -1599,6 +2127,204 @@ namespace flutter_inappwebview_plugin } } + void InAppWebView::clearSslPreferences(const std::function completionHandler) const + { + if (!webView) { + if (completionHandler) { + completionHandler(); + } + return; + } + + if (auto webView14 = webView.try_query()) { + auto hr = webView14->ClearServerCertificateErrorActions(Callback( + [completionHandler](HRESULT errorCode) + { + failedAndLog(errorCode); + if (completionHandler) { + completionHandler(); + } + return S_OK; + } + ).Get()); + + if (failedAndLog(hr) && completionHandler) { + completionHandler(); + } + return; + } + + if (completionHandler) { + completionHandler(); + } + } + + bool InAppWebView::isInterfaceSupported(const std::string& interfaceName) const + { + if (!webView) { + return false; + } + + if (string_equals(interfaceName, "ICoreWebView2") || starts_with(interfaceName, std::string{ "ICoreWebView2_" })) { + switch (string_hash(interfaceName)) { + case string_hash("ICoreWebView2"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_2"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_3"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_4"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_5"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_6"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_7"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_8"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_9"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_10"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_11"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_12"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_13"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_14"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_15"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_16"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_17"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_18"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_19"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_20"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_21"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_22"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_23"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_24"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_25"): + return webView.try_query() != nullptr; + case string_hash("ICoreWebView2_26"): + return webView.try_query() != nullptr; + default: + return false; + } + } + + wil::com_ptr webView2Settings; + if (succeededOrLog(webView->get_Settings(&webView2Settings))) { + if (starts_with(interfaceName, std::string{ "ICoreWebView2Settings" })) { + switch (string_hash(interfaceName)) { + case string_hash("ICoreWebView2Settings"): + return webView2Settings.try_query() != nullptr; + case string_hash("ICoreWebView2Settings2"): + return webView2Settings.try_query() != nullptr; + case string_hash("ICoreWebView2Settings3"): + return webView2Settings.try_query() != nullptr; + case string_hash("ICoreWebView2Settings4"): + return webView2Settings.try_query() != nullptr; + case string_hash("ICoreWebView2Settings5"): + return webView2Settings.try_query() != nullptr; + case string_hash("ICoreWebView2Settings6"): + return webView2Settings.try_query() != nullptr; + case string_hash("ICoreWebView2Settings7"): + return webView2Settings.try_query() != nullptr; + case string_hash("ICoreWebView2Settings8"): + return webView2Settings.try_query() != nullptr; + case string_hash("ICoreWebView2Settings9"): + return webView2Settings.try_query() != nullptr; + default: + return false; + } + } + } + + if (starts_with(interfaceName, std::string{ "ICoreWebView2Controller" }) && webViewController) { + switch (string_hash(interfaceName)) { + case string_hash("ICoreWebView2Controller"): + return webViewController.try_query() != nullptr; + case string_hash("ICoreWebView2Controller2"): + return webViewController.try_query() != nullptr; + case string_hash("ICoreWebView2Controller3"): + return webViewController.try_query() != nullptr; + case string_hash("ICoreWebView2Controller4"): + return webViewController.try_query() != nullptr; + default: + return false; + } + } + + if (starts_with(interfaceName, std::string{ "ICoreWebView2CompositionController" }) && webViewCompositionController) { + switch (string_hash(interfaceName)) { + case string_hash("ICoreWebView2CompositionController"): + return webViewCompositionController.try_query() != nullptr; + case string_hash("ICoreWebView2CompositionController2"): + return webViewCompositionController.try_query() != nullptr; + case string_hash("ICoreWebView2CompositionController3"): + return webViewCompositionController.try_query() != nullptr; + case string_hash("ICoreWebView2CompositionController4"): + return webViewCompositionController.try_query() != nullptr; + default: + return false; + } + } + + if (starts_with(interfaceName, std::string{ "ICoreWebView2Environment" }) && webViewEnv) { + switch (string_hash(interfaceName)) { + case string_hash("ICoreWebView2Environment"): + return webViewEnv.try_query() != nullptr; + case string_hash("ICoreWebView2Environment2"): + return webViewEnv.try_query() != nullptr; + case string_hash("ICoreWebView2Environment3"): + return webViewEnv.try_query() != nullptr; + case string_hash("ICoreWebView2Environment4"): + return webViewEnv.try_query() != nullptr; + case string_hash("ICoreWebView2Environment5"): + return webViewEnv.try_query() != nullptr; + case string_hash("ICoreWebView2Environment6"): + return webViewEnv.try_query() != nullptr; + case string_hash("ICoreWebView2Environment7"): + return webViewEnv.try_query() != nullptr; + case string_hash("ICoreWebView2Environment8"): + return webViewEnv.try_query() != nullptr; + case string_hash("ICoreWebView2Environment9"): + return webViewEnv.try_query() != nullptr; + case string_hash("ICoreWebView2Environment10"): + return webViewEnv.try_query() != nullptr; + case string_hash("ICoreWebView2Environment11"): + return webViewEnv.try_query() != nullptr; + case string_hash("ICoreWebView2Environment12"): + return webViewEnv.try_query() != nullptr; + case string_hash("ICoreWebView2Environment13"): + return webViewEnv.try_query() != nullptr; + case string_hash("ICoreWebView2Environment14"): + return webViewEnv.try_query() != nullptr; + default: + return false; + } + } + + return false; + } + + double InAppWebView::getZoomScale() const + { + return zoomScaleFactor_; + } + // flutter_view void InAppWebView::setSurfaceSize(size_t width, size_t height, float scale_factor) { @@ -1634,7 +2360,6 @@ namespace flutter_inappwebview_plugin } } - void InAppWebView::setPosition(size_t x, size_t y, float scale_factor) { if (!webViewController || !plugin || !plugin->registrar) { @@ -1665,7 +2390,6 @@ namespace flutter_inappwebview_plugin } } - void InAppWebView::setCursorPos(double x, double y) { if (!webViewCompositionController) { @@ -1751,35 +2475,66 @@ namespace flutter_inappwebview_plugin } } - void InAppWebView::setPointerButtonState(InAppWebViewPointerButton button, bool is_down) + void InAppWebView::setPointerButtonState(InAppWebViewPointerEventKind kind, InAppWebViewPointerButton button) { if (!webViewCompositionController) { return; } - COREWEBVIEW2_MOUSE_EVENT_KIND kind; - switch (button) { - case InAppWebViewPointerButton::Primary: - virtualKeys_.setIsLeftButtonDown(is_down); - kind = is_down ? COREWEBVIEW2_MOUSE_EVENT_KIND_LEFT_BUTTON_DOWN - : COREWEBVIEW2_MOUSE_EVENT_KIND_LEFT_BUTTON_UP; + COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS eventVirtualKeys_ = COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS_NONE; + COREWEBVIEW2_MOUSE_EVENT_KIND eventKind; + UINT32 mouseData = 0; + POINT point = { 0, 0 };; + + switch (kind) { + case InAppWebViewPointerEventKind::Down: + switch (button) { + case InAppWebViewPointerButton::Primary: + virtualKeys_.setIsLeftButtonDown(true); + eventKind = COREWEBVIEW2_MOUSE_EVENT_KIND_LEFT_BUTTON_DOWN; + break; + case InAppWebViewPointerButton::Secondary: + virtualKeys_.setIsRightButtonDown(true); + eventKind = COREWEBVIEW2_MOUSE_EVENT_KIND_RIGHT_BUTTON_DOWN; + break; + case InAppWebViewPointerButton::Tertiary: + virtualKeys_.setIsMiddleButtonDown(true); + eventKind = COREWEBVIEW2_MOUSE_EVENT_KIND_MIDDLE_BUTTON_DOWN; + break; + default: + eventKind = static_cast(0); + } + eventVirtualKeys_ = virtualKeys_.state(); + point = lastCursorPos_; break; - case InAppWebViewPointerButton::Secondary: - virtualKeys_.setIsRightButtonDown(is_down); - kind = is_down ? COREWEBVIEW2_MOUSE_EVENT_KIND_RIGHT_BUTTON_DOWN - : COREWEBVIEW2_MOUSE_EVENT_KIND_RIGHT_BUTTON_UP; + case InAppWebViewPointerEventKind::Up: + switch (button) { + case InAppWebViewPointerButton::Primary: + virtualKeys_.setIsLeftButtonDown(false); + eventKind = COREWEBVIEW2_MOUSE_EVENT_KIND_LEFT_BUTTON_UP; + break; + case InAppWebViewPointerButton::Secondary: + virtualKeys_.setIsRightButtonDown(false); + eventKind = COREWEBVIEW2_MOUSE_EVENT_KIND_RIGHT_BUTTON_UP; + break; + case InAppWebViewPointerButton::Tertiary: + virtualKeys_.setIsMiddleButtonDown(false); + eventKind = COREWEBVIEW2_MOUSE_EVENT_KIND_MIDDLE_BUTTON_UP; + break; + default: + eventKind = static_cast(0); + } + eventVirtualKeys_ = virtualKeys_.state(); + point = lastCursorPos_; break; - case InAppWebViewPointerButton::Tertiary: - virtualKeys_.setIsMiddleButtonDown(is_down); - kind = is_down ? COREWEBVIEW2_MOUSE_EVENT_KIND_MIDDLE_BUTTON_DOWN - : COREWEBVIEW2_MOUSE_EVENT_KIND_MIDDLE_BUTTON_UP; + case InAppWebViewPointerEventKind::Leave: + eventKind = COREWEBVIEW2_MOUSE_EVENT_KIND_LEAVE; break; default: - kind = static_cast(0); + eventKind = static_cast(0); } - webViewCompositionController->SendMouseInput(kind, virtualKeys_.state(), 0, - lastCursorPos_); + webViewCompositionController->SendMouseInput(eventKind, eventVirtualKeys_, mouseData, point); } void InAppWebView::sendScroll(double delta, bool horizontal) @@ -1788,10 +2543,7 @@ namespace flutter_inappwebview_plugin return; } - // delta * 6 gives me a multiple of WHEEL_DELTA (120) - constexpr auto kScrollMultiplier = 6; - - auto offset = static_cast(delta * kScrollMultiplier); + auto offset = static_cast(delta * settings->scrollMultiplier); if (horizontal) { webViewCompositionController->SendMouseInput( @@ -1863,6 +2615,127 @@ namespace flutter_inappwebview_plugin return webErrorStatus >= COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_COMMON_NAME_IS_INCORRECT && webErrorStatus <= COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_IS_INVALID; } + HRESULT InAppWebView::onCallJsHandler(const bool& isMainFrame, ICoreWebView2WebMessageReceivedEventArgs* args) + { + if (!channelDelegate) { + return S_OK; + } + + wil::unique_cotaskmem_string json; + if (succeededOrLog(args->get_WebMessageAsJson(&json))) { + nlohmann::basic_json<> message; + try { + message = nlohmann::json::parse(wide_to_utf8(json.get())); + } + catch (nlohmann::json::parse_error& ex) { + debugLog("Error parsing JSON message of callHandler method: " + std::string(ex.what())); + return S_OK; + } + + if (message.is_object() && message.contains("name") && message.at("name").is_string() && message.contains("body") && message.at("body").is_object()) { + auto name = message.at("name").get(); + auto body = message.at("body").get(); + + if (name.compare("callHandler") == 0) { + if (!body.contains("handlerName") || !body.at("handlerName").is_string()) { + debugLog("handlerName is null or undefined"); + return S_OK; + } + + auto handlerName = body.at("handlerName").get(); + auto bridgeSecret = body.contains("_bridgeSecret") && body.at("_bridgeSecret").is_string() ? body.at("_bridgeSecret").get() : ""; + auto callHandlerID = body.contains("_callHandlerID") && body.at("_callHandlerID").is_number_integer() ? body.at("_callHandlerID").get() : 0; + auto origin = body.contains("origin") && body.at("origin").is_string() ? body.at("origin").get() : ""; + auto requestUrl = body.contains("requestUrl") && body.at("requestUrl").is_string() ? body.at("requestUrl").get() : ""; + auto handlerArgs = body.contains("args") && body.at("args").is_string() ? body.at("args").get() : ""; + + wil::unique_cotaskmem_string sourceUrl; + if (succeededOrLog(args->get_Source(&sourceUrl))) { + requestUrl = wide_to_utf8(sourceUrl.get()); + origin = get_origin_from_url(requestUrl); + } + + if (!string_equals(expectedBridgeSecret, bridgeSecret)) { + debugLog("Bridge access attempt with wrong secret token, possibly from malicious code from origin: " + origin); + return S_OK; + } + + bool isOriginAllowed = false; + if (settings->javaScriptHandlersOriginAllowList.has_value()) { + for (auto& allowedOrigin : settings->javaScriptHandlersOriginAllowList.value()) { + if (std::regex_match(origin, std::regex(allowedOrigin))) { + isOriginAllowed = true; + break; + } + } + } + else { + // origin is by default allowed if the allow list is null + isOriginAllowed = true; + } + if (!isOriginAllowed) { + debugLog("Bridge access attempt from an origin not allowed: " + origin); + return S_OK; + } + + if (settings->javaScriptHandlersForMainFrameOnly && !isMainFrame) { + debugLog("Bridge access attempt from a sub-frame origin: " + origin); + return S_OK; + } + + /* + boolean isInternalHandler = true; + switch (handlerName) { + default: + isInternalHandler = false; + break; + } + + if (isInternalHandler) { + evaluateJavascript("if (window." + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + "[" + std::to_string(callHandlerID) + "] != null) { \ + window." + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + "[" + std::to_string(callHandlerID) + "].resolve(); \ + delete window." + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + "[" + std::to_string(callHandlerID) + "]; \ + }", ContentWorld::page(), nullptr); + return S_OK; + } + */ + + auto callback = std::make_unique(); + callback->defaultBehaviour = [this, callHandlerID](const std::optional response) + { + std::string json = "null"; + if (response.has_value() && !response.value()->IsNull()) { + json = std::get(*(response.value())); + } + + evaluateJavascript("if (window." + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + "[" + std::to_string(callHandlerID) + "] != null) { \ + window." + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + "[" + std::to_string(callHandlerID) + "].resolve(" + json + "); \ + delete window." + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + "[" + std::to_string(callHandlerID) + "]; \ + }", ContentWorld::page(), nullptr); + }; + callback->error = [this, callHandlerID](const std::string& error_code, const std::string& error_message, const flutter::EncodableValue* error_details) + { + auto errorMessage = error_code + ", " + error_message; + debugLog(errorMessage); + + evaluateJavascript("if (window." + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + "[" + std::to_string(callHandlerID) + "] != null) { \ + window." + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + "[" + std::to_string(callHandlerID) + "].reject(new Error('" + replace_all_copy(errorMessage, "\'", "\\'") + "')); \ + delete window." + JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME() + "[" + std::to_string(callHandlerID) + "]; \ + }", ContentWorld::page(), nullptr); + }; + + auto data = std::make_unique(origin, requestUrl, isMainFrame, handlerArgs); + channelDelegate->onCallJsHandler(handlerName, std::move(data), std::move(callback)); + } + } + else { + debugLog("Invalid JSON message of callHandler method"); + } + } + + return S_OK; + } + InAppWebView::~InAppWebView() { debugLog("dealloc InAppWebView"); diff --git a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.h b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.h index 6c3c3a73e..b7b27861c 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.h +++ b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.h @@ -16,6 +16,7 @@ #include "../types/ssl_certificate.h" #include "../types/url_request.h" #include "../types/web_history.h" +#include "../utils/uuid.h" #include "../webview_environment/webview_environment.h" #include "in_app_webview_settings.h" #include "user_content_controller.h" @@ -31,7 +32,7 @@ namespace flutter_inappwebview_plugin // custom_platform_view enum class InAppWebViewPointerButton { None, Primary, Secondary, Tertiary }; - enum class InAppWebViewPointerEventKind { Activate, Down, Enter, Leave, Up, Update }; + enum class InAppWebViewPointerEventKind { Activate, Down, Enter, Leave, Up, Update, Cancel }; typedef std::function SurfaceSizeChangedCallback; typedef std::function CursorChangedCallback; @@ -126,7 +127,7 @@ namespace flutter_inappwebview_plugin void setCursorPos(double x, double y); void setPointerUpdate(int32_t pointer, InAppWebViewPointerEventKind eventKind, double x, double y, double size, double pressure); - void setPointerButtonState(InAppWebViewPointerButton button, bool isDown); + void setPointerButtonState(InAppWebViewPointerEventKind kind, InAppWebViewPointerButton button); void sendScroll(double offset, bool horizontal); void setScrollDelta(double delta_x, double delta_y); void onSurfaceSizeChanged(SurfaceSizeChangedCallback callback) @@ -176,6 +177,9 @@ namespace flutter_inappwebview_plugin void pause() const; void resume() const; void getCertificate(const std::function>)> completionHandler) const; + void clearSslPreferences(const std::function completionHandler) const; + bool isInterfaceSupported(const std::string& interfaceName) const; + double getZoomScale() const; std::string pageFrameId() const { @@ -192,14 +196,19 @@ namespace flutter_inappwebview_plugin POINT lastCursorPos_ = { 0, 0 }; VirtualKeyState virtualKeys_; + const std::string expectedBridgeSecret = get_uuid(); + bool javaScriptBridgeEnabled = true; std::map> navigationActions_ = {}; std::shared_ptr lastNavigationAction_; bool isLoading_ = false; std::string pageFrameId_; std::map, EventRegistrationToken>> devToolsProtocolEventListener_ = {}; + int64_t previousAuthRequestFailureCount = 0; + double zoomScaleFactor_ = 1.0; void registerEventHandlers(); void registerSurfaceEventHandlers(); + HRESULT onCallJsHandler(const bool& isMainFrame, ICoreWebView2WebMessageReceivedEventArgs* args); }; } #endif //FLUTTER_INAPPWEBVIEW_PLUGIN_IN_APP_WEBVIEW_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.cpp b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.cpp index 9b6850930..fb42f7bad 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.cpp +++ b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.cpp @@ -5,6 +5,7 @@ #include #include "../in_app_webview/in_app_webview_settings.h" +#include "../plugin_scripts_js/javascript_bridge_js.h" #include "../types/url_request.h" #include "../types/user_script.h" #include "../utils/flutter.h" @@ -18,33 +19,42 @@ namespace flutter_inappwebview_plugin { InAppWebViewManager::InAppWebViewManager(const FlutterInappwebviewWindowsPlugin* plugin) : plugin(plugin), - ChannelDelegate(plugin->registrar->messenger(), InAppWebViewManager::METHOD_CHANNEL_NAME), - rohelper_(std::make_unique(RO_INIT_SINGLETHREADED)) + ChannelDelegate(plugin->registrar->messenger(), InAppWebViewManager::METHOD_CHANNEL_NAME) { - if (rohelper_->WinRtAvailable()) { - DispatcherQueueOptions options{ sizeof(DispatcherQueueOptions), - DQTYPE_THREAD_CURRENT, DQTAT_COM_STA }; - - if (FAILED(rohelper_->CreateDispatcherQueueController( - options, dispatcher_queue_controller_.put()))) { - std::cerr << "Creating DispatcherQueueController failed." << std::endl; - return; - } + if (!rohelper_) { + rohelper_ = std::make_unique(RO_INIT_SINGLETHREADED); - if (!isGraphicsCaptureSessionSupported()) { - std::cerr << "Windows::Graphics::Capture::GraphicsCaptureSession is not " - "supported." - << std::endl; - return; - } + if (rohelper_->WinRtAvailable()) { + DispatcherQueueOptions options{ sizeof(DispatcherQueueOptions), + DQTYPE_THREAD_CURRENT, DQTAT_COM_STA }; + + if (FAILED(rohelper_->CreateDispatcherQueueController( + options, dispatcher_queue_controller_.put()))) { + std::cerr << "Creating DispatcherQueueController failed." << std::endl; + return; + } - graphics_context_ = std::make_unique(rohelper_.get()); - compositor_ = graphics_context_->CreateCompositor(); - valid_ = graphics_context_->IsValid(); + if (!isGraphicsCaptureSessionSupported()) { + std::cerr << "Windows::Graphics::Capture::GraphicsCaptureSession is not " + "supported." + << std::endl; + return; + } + + graphics_context_ = std::make_unique(rohelper_.get()); + compositor_ = graphics_context_->CreateCompositor(); + if (compositor_) { + // fix for KernelBase.dll RaiseFailFastException + // when app is closing + compositor_->AddRef(); + } + valid_ = graphics_context_->IsValid(); + } } windowClass_.lpszClassName = CustomPlatformView::CLASS_NAME; windowClass_.lpfnWndProc = &DefWindowProc; + windowClass_.style |= CS_NOCLOSE; RegisterClass(&windowClass_); } @@ -66,6 +76,10 @@ namespace flutter_inappwebview_plugin else if (string_equals(methodName, "dispose")) { auto id = get_fl_map_value(*arguments, "id"); if (map_contains(webViews, (uint64_t)id)) { + auto platformView = webViews.at(id).get(); + if (platformView) { + platformView->UnregisterMethodCallHandler(); + } webViews.erase(id); } result->Success(); @@ -75,6 +89,14 @@ namespace flutter_inappwebview_plugin disposeKeepAlive(keepAliveId); result->Success(); } + else if (string_equals(methodName, "setJavaScriptBridgeName")) { + auto bridgeName = get_fl_map_value(*arguments, "bridgeName"); + JavaScriptBridgeJS::set_JAVASCRIPT_BRIDGE_NAME(bridgeName); + result->Success(); + } + else if (string_equals(methodName, "getJavaScriptBridgeName")) { + result->Success(JavaScriptBridgeJS::get_JAVASCRIPT_BRIDGE_NAME()); + } else { result->NotImplemented(); } @@ -84,6 +106,11 @@ namespace flutter_inappwebview_plugin { auto result_ = std::shared_ptr>(std::move(result)); + if (!plugin) { + result_->Error("0", "Cannot create the InAppWebView instance!"); + return; + } + auto settingsMap = get_fl_map_value(*arguments, "initialSettings"); auto urlRequestMap = get_optional_fl_map_value(*arguments, "initialUrlRequest"); auto initialFile = get_optional_fl_map_value(*arguments, "initialFile"); @@ -126,7 +153,7 @@ namespace flutter_inappwebview_plugin wil::com_ptr webViewController, wil::com_ptr webViewCompositionController) { - if (webViewEnv && webViewController && webViewCompositionController) { + if (plugin && webViewEnv && webViewController && webViewCompositionController) { std::optional>> initialUserScripts = initialUserScriptList.has_value() ? functional_map(initialUserScriptList.value(), [](const flutter::EncodableValue& map) { return std::make_shared(std::get(map)); }) : std::optional>>{}; @@ -186,6 +213,10 @@ namespace flutter_inappwebview_plugin void InAppWebViewManager::disposeKeepAlive(const std::string& keepAliveId) { if (map_contains(keepAliveWebViews, keepAliveId)) { + auto platformView = keepAliveWebViews.at(keepAliveId).get(); + if (platformView) { + platformView->UnregisterMethodCallHandler(); + } keepAliveWebViews.erase(keepAliveId); } } diff --git a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.h b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.h index f48c799e7..b11a38074 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.h +++ b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.h @@ -52,13 +52,13 @@ namespace flutter_inappwebview_plugin void createInAppWebView(const flutter::EncodableMap* arguments, std::unique_ptr> result); void disposeKeepAlive(const std::string& keepAliveId); private: - std::unique_ptr rohelper_; - winrt::com_ptr + inline static std::shared_ptr rohelper_ = nullptr; + inline static winrt::com_ptr dispatcher_queue_controller_; - std::unique_ptr graphics_context_; - winrt::com_ptr compositor_; + inline static std::unique_ptr graphics_context_ = nullptr; + inline static winrt::com_ptr compositor_; WNDCLASS windowClass_ = {}; - bool valid_ = false; + inline static bool valid_ = false; }; } #endif //FLUTTER_INAPPWEBVIEW_PLUGIN_IN_APP_WEBVIEW_MANAGER_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_settings.cpp b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_settings.cpp index 387c919d1..7a2e5218d 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_settings.cpp +++ b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_settings.cpp @@ -3,7 +3,6 @@ #include "in_app_webview.h" #include "in_app_webview_settings.h" -#include #include namespace flutter_inappwebview_plugin @@ -25,6 +24,33 @@ namespace flutter_inappwebview_plugin isInspectable = get_fl_map_value(encodableMap, "isInspectable", isInspectable); disableContextMenu = get_fl_map_value(encodableMap, "disableContextMenu", disableContextMenu); incognito = get_fl_map_value(encodableMap, "incognito", incognito); + if (fl_map_contains_not_null(encodableMap, "javaScriptHandlersOriginAllowList")) { + javaScriptHandlersOriginAllowList = get_optional_fl_map_value>(encodableMap, "javaScriptHandlersOriginAllowList"); + } + javaScriptHandlersForMainFrameOnly = get_fl_map_value(encodableMap, "javaScriptHandlersForMainFrameOnly", javaScriptHandlersForMainFrameOnly); + javaScriptBridgeEnabled = get_fl_map_value(encodableMap, "javaScriptBridgeEnabled", javaScriptBridgeEnabled); + if (fl_map_contains_not_null(encodableMap, "javaScriptBridgeOriginAllowList")) { + javaScriptBridgeOriginAllowList = get_optional_fl_map_value>(encodableMap, "javaScriptBridgeOriginAllowList"); + } + if (fl_map_contains_not_null(encodableMap, "javaScriptBridgeForMainFrameOnly")) { + javaScriptBridgeForMainFrameOnly = get_fl_map_value(encodableMap, "javaScriptBridgeForMainFrameOnly"); + } + if (fl_map_contains_not_null(encodableMap, "pluginScriptsOriginAllowList")) { + pluginScriptsOriginAllowList = get_optional_fl_map_value>(encodableMap, "pluginScriptsOriginAllowList"); + } + pluginScriptsForMainFrameOnly = get_fl_map_value(encodableMap, "pluginScriptsForMainFrameOnly", pluginScriptsForMainFrameOnly); + scrollMultiplier = get_fl_map_value(encodableMap, "scrollMultiplier", scrollMultiplier); + disableDefaultErrorPage = get_fl_map_value(encodableMap, "disableDefaultErrorPage", disableDefaultErrorPage); + statusBarEnabled = get_fl_map_value(encodableMap, "statusBarEnabled", statusBarEnabled); + browserAcceleratorKeysEnabled = get_fl_map_value(encodableMap, "browserAcceleratorKeysEnabled", browserAcceleratorKeysEnabled); + generalAutofillEnabled = get_fl_map_value(encodableMap, "generalAutofillEnabled", generalAutofillEnabled); + passwordAutosaveEnabled = get_fl_map_value(encodableMap, "passwordAutosaveEnabled", passwordAutosaveEnabled); + pinchZoomEnabled = get_fl_map_value(encodableMap, "pinchZoomEnabled", pinchZoomEnabled); + allowsBackForwardNavigationGestures = get_fl_map_value(encodableMap, "allowsBackForwardNavigationGestures", allowsBackForwardNavigationGestures); + hiddenPdfToolbarItems = get_fl_map_value(encodableMap, "hiddenPdfToolbarItems", hiddenPdfToolbarItems); + reputationCheckingRequired = get_fl_map_value(encodableMap, "reputationCheckingRequired", reputationCheckingRequired); + nonClientRegionSupportEnabled = get_fl_map_value(encodableMap, "nonClientRegionSupportEnabled", nonClientRegionSupportEnabled); + handleAcceleratorKeyPressed = get_fl_map_value(encodableMap, "handleAcceleratorKeyPressed", handleAcceleratorKeyPressed); } flutter::EncodableMap InAppWebViewSettings::toEncodableMap() const @@ -41,6 +67,25 @@ namespace flutter_inappwebview_plugin {"isInspectable", isInspectable}, {"disableContextMenu", disableContextMenu}, {"incognito", incognito}, + {"javaScriptHandlersOriginAllowList", make_fl_value(javaScriptHandlersOriginAllowList)}, + {"javaScriptHandlersForMainFrameOnly", javaScriptHandlersForMainFrameOnly}, + {"javaScriptBridgeEnabled", javaScriptBridgeEnabled}, + {"javaScriptBridgeOriginAllowList", make_fl_value(javaScriptBridgeOriginAllowList)}, + {"javaScriptBridgeForMainFrameOnly", make_fl_value(javaScriptBridgeForMainFrameOnly)}, + {"pluginScriptsOriginAllowList", make_fl_value(pluginScriptsOriginAllowList)}, + {"pluginScriptsForMainFrameOnly", pluginScriptsForMainFrameOnly}, + {"scrollMultiplier", scrollMultiplier}, + {"disableDefaultErrorPage", disableDefaultErrorPage}, + {"statusBarEnabled", statusBarEnabled}, + {"browserAcceleratorKeysEnabled", browserAcceleratorKeysEnabled}, + {"generalAutofillEnabled", generalAutofillEnabled}, + {"passwordAutosaveEnabled", passwordAutosaveEnabled}, + {"pinchZoomEnabled", pinchZoomEnabled}, + {"allowsBackForwardNavigationGestures", allowsBackForwardNavigationGestures}, + {"hiddenPdfToolbarItems", hiddenPdfToolbarItems}, + {"reputationCheckingRequired", reputationCheckingRequired}, + {"nonClientRegionSupportEnabled", nonClientRegionSupportEnabled}, + {"handleAcceleratorKeyPressed", handleAcceleratorKeyPressed} }; } @@ -67,14 +112,74 @@ namespace flutter_inappwebview_plugin if (SUCCEEDED(settings->get_AreDefaultContextMenusEnabled(&areDefaultContextMenusEnabled))) { settingsMap["disableContextMenu"] = !(bool)areDefaultContextMenusEnabled; } + BOOL isBuiltInErrorPageEnabled; + if (SUCCEEDED(settings->get_IsBuiltInErrorPageEnabled(&isBuiltInErrorPageEnabled))) { + settingsMap["disableDefaultErrorPage"] = !(bool)isBuiltInErrorPageEnabled; + } + BOOL isStatusBarEnabled; + if (SUCCEEDED(settings->get_IsBuiltInErrorPageEnabled(&isStatusBarEnabled))) { + settingsMap["statusBarEnabled"] = (bool)isStatusBarEnabled; + } - wil::com_ptr settings2; - if (SUCCEEDED(settings->QueryInterface(IID_PPV_ARGS(&settings2)))) { + if (auto settings2 = settings.try_query()) { wil::unique_cotaskmem_string realUserAgent; if (SUCCEEDED(settings2->get_UserAgent(&realUserAgent))) { settingsMap["userAgent"] = wide_to_utf8(realUserAgent.get()); } } + + if (auto settings3 = settings.try_query()) { + BOOL areBrowserAcceleratorKeysEnabled; + if (SUCCEEDED(settings3->get_AreBrowserAcceleratorKeysEnabled(&areBrowserAcceleratorKeysEnabled))) { + settingsMap["browserAcceleratorKeysEnabled"] = (bool)areBrowserAcceleratorKeysEnabled; + } + } + + if (auto settings4 = settings.try_query()) { + BOOL isGeneralAutofillEnabled; + if (SUCCEEDED(settings4->get_IsGeneralAutofillEnabled(&isGeneralAutofillEnabled))) { + settingsMap["generalAutofillEnabled"] = (bool)isGeneralAutofillEnabled; + } + BOOL isPasswordAutosaveEnabled; + if (SUCCEEDED(settings4->get_IsPasswordAutosaveEnabled(&isPasswordAutosaveEnabled))) { + settingsMap["passwordAutosaveEnabled"] = (bool)isPasswordAutosaveEnabled; + } + } + + if (auto settings5 = settings.try_query()) { + BOOL isPinchZoomEnabled; + if (SUCCEEDED(settings5->get_IsPinchZoomEnabled(&isPinchZoomEnabled))) { + settingsMap["pinchZoomEnabled"] = (bool)isPinchZoomEnabled; + } + } + + if (auto settings6 = settings.try_query()) { + BOOL isSwipeNavigationEnabled; + if (SUCCEEDED(settings6->get_IsSwipeNavigationEnabled(&isSwipeNavigationEnabled))) { + settingsMap["allowsBackForwardNavigationGestures"] = (bool)isSwipeNavigationEnabled; + } + } + + if (auto settings7 = settings.try_query()) { + COREWEBVIEW2_PDF_TOOLBAR_ITEMS realHiddenPdfToolbarItems; + if (SUCCEEDED(settings7->get_HiddenPdfToolbarItems(&realHiddenPdfToolbarItems))) { + settingsMap["hiddenPdfToolbarItems"] = (int64_t)realHiddenPdfToolbarItems; + } + } + + if (auto settings8 = settings.try_query()) { + BOOL isReputationCheckingRequired; + if (SUCCEEDED(settings8->get_IsReputationCheckingRequired(&isReputationCheckingRequired))) { + settingsMap["reputationCheckingRequired"] = (bool)isReputationCheckingRequired; + } + } + + if (auto settings9 = settings.try_query()) { + BOOL isNonClientRegionSupportEnabled; + if (SUCCEEDED(settings9->get_IsNonClientRegionSupportEnabled(&isNonClientRegionSupportEnabled))) { + settingsMap["nonClientRegionSupportEnabled"] = (bool)isNonClientRegionSupportEnabled; + } + } } } return settingsMap; diff --git a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_settings.h b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_settings.h index 92c9db08e..7eab9ea23 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_settings.h +++ b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_settings.h @@ -1,7 +1,9 @@ #ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_IN_APP_WEBVIEW_SETTINGS_H_ #define FLUTTER_INAPPWEBVIEW_PLUGIN_IN_APP_WEBVIEW_SETTINGS_H_ +#include #include +#include namespace flutter_inappwebview_plugin { @@ -21,6 +23,25 @@ namespace flutter_inappwebview_plugin bool isInspectable = true; bool disableContextMenu = false; bool incognito = false; + std::optional> javaScriptHandlersOriginAllowList = std::optional>{}; + bool javaScriptHandlersForMainFrameOnly = false; + bool javaScriptBridgeEnabled = true; + std::optional> javaScriptBridgeOriginAllowList = std::optional>{}; + std::optional javaScriptBridgeForMainFrameOnly = std::optional{}; + std::optional> pluginScriptsOriginAllowList = std::optional>{}; + bool pluginScriptsForMainFrameOnly = false; + int64_t scrollMultiplier = 1; + bool disableDefaultErrorPage = false; + bool statusBarEnabled = true; + bool browserAcceleratorKeysEnabled = true; + bool generalAutofillEnabled = true; + bool passwordAutosaveEnabled = false; + bool pinchZoomEnabled = true; + bool allowsBackForwardNavigationGestures = true; + int64_t hiddenPdfToolbarItems = COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_NONE; + bool reputationCheckingRequired = true; + bool nonClientRegionSupportEnabled = false; + bool handleAcceleratorKeyPressed = false; InAppWebViewSettings(); InAppWebViewSettings(const flutter::EncodableMap& encodableMap); diff --git a/flutter_inappwebview_windows/windows/in_app_webview/user_content_controller.cpp b/flutter_inappwebview_windows/windows/in_app_webview/user_content_controller.cpp index 9cbe2761f..35e7284c5 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/user_content_controller.cpp +++ b/flutter_inappwebview_windows/windows/in_app_webview/user_content_controller.cpp @@ -343,11 +343,9 @@ namespace flutter_inappwebview_plugin std::string source = userScript->source; if (userScript->injectionTime == UserScriptInjectionTime::atDocumentEnd) { - source = replace_all_copy(USER_SCRIPTS_AT_DOCUMENT_END_WRAPPER_JS_SOURCE, VAR_PLACEHOLDER_VALUE, source); - std::ostringstream address; - address << std::addressof(userScript); - replace_all(source, VAR_PLACEHOLDER_MEMORY_ADDRESS_VALUE, address.str()); + source = "if (document.readyState === 'complete') { " + source + "} else { window.addEventListener('load', function() { " + source + " }); }"; } + source = UserContentController::wrapSourceCodeAddChecks(source, userScript); nlohmann::json parameters = { {"source", source} @@ -421,6 +419,44 @@ namespace flutter_inappwebview_plugin } } + std::string UserContentController::wrapSourceCodeAddChecks(const std::string& source, const std::shared_ptr userScript) + { + auto allowedOriginRules = userScript->allowedOriginRules; + auto forMainFrameOnly = userScript->forMainFrameOnly; + + std::string ifStatement = "if ("; + + if (allowedOriginRules.has_value() && !vector_contains(allowedOriginRules.value(), "*")) { + if (allowedOriginRules.value().empty()) { + // return empty source string if allowedOriginRules is an empty list. + // an empty list means that this UserScript is not allowed for any origin. + return ""; + } + + std::string jsRegExpArray = "["; + for (const auto& allowedOriginRule : allowedOriginRules.value()) { + if (jsRegExpArray.length() > 1) { + jsRegExpArray += ", "; + } + jsRegExpArray += "new RegExp('" + replace_all_copy(allowedOriginRule, "\'", "\\'") + "')"; + } + + if (jsRegExpArray.length() > 1) { + jsRegExpArray += "]"; + ifStatement += jsRegExpArray + ".some(function(rx) { return rx.test(window.location.origin); })"; + } + } + + if (forMainFrameOnly) { + if (ifStatement.length() > 4) { + ifStatement += " && "; + } + ifStatement += "window === window.top"; + } + + return ifStatement.length() > 4 ? ifStatement + ") { " + source + "}" : source; + } + UserContentController::~UserContentController() { debugLog("dealloc UserContentController"); diff --git a/flutter_inappwebview_windows/windows/in_app_webview/user_content_controller.h b/flutter_inappwebview_windows/windows/in_app_webview/user_content_controller.h index a65929134..c5045c3ed 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/user_content_controller.h +++ b/flutter_inappwebview_windows/windows/in_app_webview/user_content_controller.h @@ -5,6 +5,7 @@ #include #include +#include "../plugin_scripts_js/javascript_bridge_js.h" #include "../plugin_scripts_js/javascript_bridge_js.h" #include "../plugin_scripts_js/plugin_scripts_util.h" #include "../types/content_world.h" @@ -15,13 +16,6 @@ namespace flutter_inappwebview_plugin { class InAppWebView; - const std::string USER_SCRIPTS_AT_DOCUMENT_END_WRAPPER_JS_SOURCE = "window.addEventListener('load', () => { \ - if (window." + JAVASCRIPT_BRIDGE_NAME + " != null && (window." + JAVASCRIPT_BRIDGE_NAME + "._userScript" + VAR_PLACEHOLDER_MEMORY_ADDRESS_VALUE + "AtDocumentEndLoaded == null || !window." + JAVASCRIPT_BRIDGE_NAME + "._userScript" + VAR_PLACEHOLDER_MEMORY_ADDRESS_VALUE + "AtDocumentEndLoaded)) { \ - window." + JAVASCRIPT_BRIDGE_NAME + "._userScript" + VAR_PLACEHOLDER_MEMORY_ADDRESS_VALUE + "AtDocumentEndLoaded = true; \ - " + VAR_PLACEHOLDER_VALUE + " \ - } \ - });"; - class UserContentController { public: @@ -51,6 +45,7 @@ namespace flutter_inappwebview_plugin void registerEventHandlers(); void createContentWorld(const std::shared_ptr contentWorld, const std::function completionHandler); + private: InAppWebView* webView_; @@ -73,6 +68,8 @@ namespace flutter_inappwebview_plugin void removeScriptFromWebView(std::shared_ptr userScript, const std::function completionHandler) const; void addPluginScriptsIfRequired(const std::shared_ptr contentWorld); + + static std::string wrapSourceCodeAddChecks(const std::string& source, const std::shared_ptr userScript); }; } #endif //FLUTTER_INAPPWEBVIEW_PLUGIN_USER_CONTENT_CONTROLLER_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/in_app_webview/webview_channel_delegate.cpp b/flutter_inappwebview_windows/windows/in_app_webview/webview_channel_delegate.cpp index df6a4bc8a..c09a23689 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/webview_channel_delegate.cpp +++ b/flutter_inappwebview_windows/windows/in_app_webview/webview_channel_delegate.cpp @@ -54,7 +54,7 @@ namespace flutter_inappwebview_plugin { decodeResult = [](const flutter::EncodableValue* value) { - return std::make_shared(std::get(*value)); + return value == nullptr || value->IsNull() ? std::optional>{} : std::make_shared(std::get(*value)); }; } @@ -74,6 +74,38 @@ namespace flutter_inappwebview_plugin }; } + WebViewChannelDelegate::ReceivedHttpAuthRequestCallback::ReceivedHttpAuthRequestCallback() + { + decodeResult = [](const flutter::EncodableValue* value) + { + return value == nullptr || value->IsNull() ? std::optional>{} : std::make_shared(std::get(*value)); + }; + } + + WebViewChannelDelegate::ReceivedClientCertRequestCallback::ReceivedClientCertRequestCallback() + { + decodeResult = [](const flutter::EncodableValue* value) + { + return value == nullptr || value->IsNull() ? std::optional>{} : std::make_shared(std::get(*value)); + }; + } + + WebViewChannelDelegate::ReceivedServerTrustAuthRequestCallback::ReceivedServerTrustAuthRequestCallback() + { + decodeResult = [](const flutter::EncodableValue* value) + { + return value == nullptr || value->IsNull() ? std::optional>{} : std::make_shared(std::get(*value)); + }; + } + + WebViewChannelDelegate::DownloadStartRequestCallback::DownloadStartRequestCallback() + { + decodeResult = [](const flutter::EncodableValue* value) + { + return value == nullptr || value->IsNull() ? std::optional>{} : std::make_shared(std::get(*value)); + }; + } + void WebViewChannelDelegate::HandleMethodCall(const flutter::MethodCall& method_call, std::unique_ptr> result) { @@ -269,6 +301,20 @@ namespace flutter_inappwebview_plugin result_->Success(data.has_value() ? data.value()->toEncodableMap() : make_fl_value()); }); } + else if (string_equals(methodName, "clearSslPreferences")) { + auto result_ = std::shared_ptr>(std::move(result)); + webView->clearSslPreferences([result_ = std::move(result_)]() + { + result_->Success(); + }); + } + else if (string_equals(methodName, "isInterfaceSupported")) { + auto interfaceName = get_fl_map_value(arguments, "interface"); + result->Success(webView->isInterfaceSupported(interfaceName)); + } + else if (string_equals(methodName, "getZoomScale")) { + result->Success(webView->getZoomScale()); + } // for inAppBrowser else if (webView->inAppBrowser && string_equals(methodName, "show")) { webView->inAppBrowser->show(); @@ -377,7 +423,7 @@ namespace flutter_inappwebview_plugin channel->InvokeMethod("onUpdateVisitedHistory", std::move(arguments)); } - void WebViewChannelDelegate::onCallJsHandler(const std::string& handlerName, const std::string& args, std::unique_ptr callback) const + void WebViewChannelDelegate::onCallJsHandler(const std::string& handlerName, const std::unique_ptr data, std::unique_ptr callback) const { if (!channel) { callback->defaultBehaviour(std::nullopt); @@ -386,7 +432,7 @@ namespace flutter_inappwebview_plugin auto arguments = std::make_unique(flutter::EncodableMap{ {"handlerName", handlerName}, - {"args", args} + {"data", data->toEncodableMap()} }); channel->InvokeMethod("onCallJsHandler", std::move(arguments), std::move(callback)); } @@ -488,6 +534,114 @@ namespace flutter_inappwebview_plugin channel->InvokeMethod("onLoadResourceWithCustomScheme", std::move(arguments), std::move(callback)); } + void WebViewChannelDelegate::onReceivedHttpAuthRequest(std::shared_ptr challenge, std::unique_ptr callback) const + { + if (!channel) { + callback->defaultBehaviour(std::nullopt); + return; + } + + auto arguments = std::make_unique(challenge->toEncodableMap()); + channel->InvokeMethod("onReceivedHttpAuthRequest", std::move(arguments), std::move(callback)); + } + + void WebViewChannelDelegate::onReceivedClientCertRequest(std::shared_ptr challenge, std::unique_ptr callback) const + { + if (!channel) { + callback->defaultBehaviour(std::nullopt); + return; + } + + auto arguments = std::make_unique(challenge->toEncodableMap()); + channel->InvokeMethod("onReceivedClientCertRequest", std::move(arguments), std::move(callback)); + } + + void WebViewChannelDelegate::onReceivedServerTrustAuthRequest(std::shared_ptr challenge, std::unique_ptr callback) const + { + if (!channel) { + callback->defaultBehaviour(std::nullopt); + return; + } + + auto arguments = std::make_unique(challenge->toEncodableMap()); + channel->InvokeMethod("onReceivedServerTrustAuthRequest", std::move(arguments), std::move(callback)); + } + + void WebViewChannelDelegate::onRenderProcessGone(const std::shared_ptr detail) const + { + if (!channel) { + return; + } + + auto arguments = std::make_unique(detail->toEncodableMap()); + channel->InvokeMethod("onDevToolsProtocolEventReceived", std::move(arguments)); + } + + void WebViewChannelDelegate::onRenderProcessUnresponsive(const std::optional& url) const + { + if (!channel) { + return; + } + + auto arguments = std::make_unique(flutter::EncodableMap{ + {"url", make_fl_value(url)}, + }); + channel->InvokeMethod("onRenderProcessUnresponsive", std::move(arguments)); + } + void WebViewChannelDelegate::onWebContentProcessDidTerminate() const + { + if (!channel) { + return; + } + + auto arguments = std::make_unique(); + channel->InvokeMethod("onWebContentProcessDidTerminate", std::move(arguments)); + } + + void WebViewChannelDelegate::onProcessFailed(const std::shared_ptr detail) const + { + if (!channel) { + return; + } + + auto arguments = std::make_unique(detail->toEncodableMap()); + channel->InvokeMethod("onProcessFailed", std::move(arguments)); + } + + void WebViewChannelDelegate::onDownloadStarting(std::shared_ptr request, std::unique_ptr callback) const + { + if (!channel) { + callback->defaultBehaviour(std::nullopt); + return; + } + + auto arguments = std::make_unique(request->toEncodableMap()); + channel->InvokeMethod("onDownloadStarting", std::move(arguments), std::move(callback)); + } + + void WebViewChannelDelegate::onAcceleratorKeyPressed(std::shared_ptr detail) const + { + if (!channel) { + return; + } + + auto arguments = std::make_unique(detail->toEncodableMap()); + channel->InvokeMethod("onAcceleratorKeyPressed", std::move(arguments)); + } + + void WebViewChannelDelegate::onZoomScaleChanged(const double& oldScale, const double& newScale) const + { + if (!channel) { + return; + } + + auto arguments = std::make_unique(flutter::EncodableMap{ + {"oldScale", make_fl_value(oldScale)}, + {"newScale", make_fl_value(newScale)}, + }); + channel->InvokeMethod("onZoomScaleChanged", std::move(arguments)); + } + WebViewChannelDelegate::~WebViewChannelDelegate() { debugLog("dealloc WebViewChannelDelegate"); diff --git a/flutter_inappwebview_windows/windows/in_app_webview/webview_channel_delegate.h b/flutter_inappwebview_windows/windows/in_app_webview/webview_channel_delegate.h index 005e782dd..3421a9fbe 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/webview_channel_delegate.h +++ b/flutter_inappwebview_windows/windows/in_app_webview/webview_channel_delegate.h @@ -1,15 +1,26 @@ #ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_WEBVIEW_CHANNEL_DELEGATE_H_ #define FLUTTER_INAPPWEBVIEW_PLUGIN_WEBVIEW_CHANNEL_DELEGATE_H_ -#include #include +#include "../types/accelerator_key_pressed_detail.h" #include "../types/base_callback_result.h" #include "../types/channel_delegate.h" +#include "../types/client_cert_challenge.h" +#include "../types/client_cert_response.h" #include "../types/create_window_action.h" #include "../types/custom_scheme_response.h" +#include "../types/download_start_request.h" +#include "../types/download_start_response.h" +#include "../types/http_auth_response.h" +#include "../types/http_authentication_challenge.h" +#include "../types/javascript_handler_function_data.h" #include "../types/navigation_action.h" #include "../types/permission_response.h" +#include "../types/process_failed_detail.h" +#include "../types/render_process_gone_detail.h" +#include "../types/server_trust_auth_response.h" +#include "../types/server_trust_challenge.h" #include "../types/web_resource_error.h" #include "../types/web_resource_request.h" #include "../types/web_resource_response.h" @@ -18,7 +29,7 @@ namespace flutter_inappwebview_plugin { class InAppWebView; - enum NavigationActionPolicy { cancel = 0, allow = 1 }; + enum class NavigationActionPolicy { cancel = 0, allow = 1 }; class WebViewChannelDelegate : public ChannelDelegate { @@ -61,6 +72,30 @@ namespace flutter_inappwebview_plugin ~LoadResourceWithCustomSchemeCallback() = default; }; + class ReceivedHttpAuthRequestCallback : public BaseCallbackResult> { + public: + ReceivedHttpAuthRequestCallback(); + ~ReceivedHttpAuthRequestCallback() = default; + }; + + class ReceivedClientCertRequestCallback : public BaseCallbackResult> { + public: + ReceivedClientCertRequestCallback(); + ~ReceivedClientCertRequestCallback() = default; + }; + + class ReceivedServerTrustAuthRequestCallback : public BaseCallbackResult> { + public: + ReceivedServerTrustAuthRequestCallback(); + ~ReceivedServerTrustAuthRequestCallback() = default; + }; + + class DownloadStartRequestCallback : public BaseCallbackResult> { + public: + DownloadStartRequestCallback(); + ~DownloadStartRequestCallback() = default; + }; + WebViewChannelDelegate(InAppWebView* webView, flutter::BinaryMessenger* messenger); WebViewChannelDelegate(InAppWebView* webView, flutter::BinaryMessenger* messenger, const std::string& name); ~WebViewChannelDelegate(); @@ -77,7 +112,7 @@ namespace flutter_inappwebview_plugin void onReceivedHttpError(std::shared_ptr request, std::shared_ptr error) const; void onTitleChanged(const std::optional& title) const; void onUpdateVisitedHistory(const std::optional& url, const std::optional& isReload) const; - void onCallJsHandler(const std::string& handlerName, const std::string& args, std::unique_ptr callback) const; + void onCallJsHandler(const std::string& handlerName, const std::unique_ptr data, std::unique_ptr callback) const; void onConsoleMessage(const std::string& message, const int64_t& messageLevel) const; void onDevToolsProtocolEventReceived(const std::string& eventName, const std::string& data) const; void onCreateWindow(std::shared_ptr createWindowAction, std::unique_ptr callback) const; @@ -85,6 +120,16 @@ namespace flutter_inappwebview_plugin void onPermissionRequest(const std::string& origin, const std::vector& resources, std::unique_ptr callback) const; void shouldInterceptRequest(std::shared_ptr request, std::unique_ptr callback) const; void onLoadResourceWithCustomScheme(std::shared_ptr request, std::unique_ptr callback) const; + void onReceivedHttpAuthRequest(std::shared_ptr challenge, std::unique_ptr callback) const; + void onReceivedClientCertRequest(std::shared_ptr challenge, std::unique_ptr callback) const; + void onReceivedServerTrustAuthRequest(std::shared_ptr challenge, std::unique_ptr callback) const; + void onRenderProcessGone(const std::shared_ptr detail) const; + void onRenderProcessUnresponsive(const std::optional& url) const; + void onWebContentProcessDidTerminate() const; + void onProcessFailed(const std::shared_ptr detail) const; + void onDownloadStarting(std::shared_ptr request, std::unique_ptr callback) const; + void onAcceleratorKeyPressed(std::shared_ptr detail) const; + void onZoomScaleChanged(const double& oldScale, const double& newScale) const; }; } diff --git a/flutter_inappwebview_windows/windows/platform_util.cpp b/flutter_inappwebview_windows/windows/platform_util.cpp new file mode 100644 index 000000000..4de817672 --- /dev/null +++ b/flutter_inappwebview_windows/windows/platform_util.cpp @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include + +#include "in_app_webview/in_app_webview_manager.h" +#include "platform_util.h" +#include "types/callbacks_complete.h" +#include "utils/flutter.h" +#include "utils/log.h" + +namespace flutter_inappwebview_plugin +{ + using namespace Microsoft::WRL; + + PlatformUtil::PlatformUtil(const FlutterInappwebviewWindowsPlugin* plugin) + : plugin(plugin), ChannelDelegate(plugin->registrar->messenger(), PlatformUtil::METHOD_CHANNEL_NAME_PREFIX) + {} + + void PlatformUtil::HandleMethodCall(const flutter::MethodCall& method_call, + std::unique_ptr> result) + { + result->NotImplemented(); + } + + void PlatformUtil::_EmitEvent(std::string eventName) + { + if (channel == nullptr) + return; + flutter::EncodableMap args = flutter::EncodableMap(); + args[flutter::EncodableValue("eventName")] = flutter::EncodableValue(eventName); + channel->InvokeMethod( + "onEvent", std::make_unique(args)); + } + + std::optional PlatformUtil::HandleWindowProc( + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam) noexcept + { + std::optional result = std::nullopt; + + if (message == WM_MOVING) { + window_is_moving_ = true; + if (!window_start_move_sent_) { + window_start_move_sent_ = true; + _EmitEvent("onWindowStartMove"); + } + _EmitEvent("onWindowMove"); + } + else if (message == WM_EXITSIZEMOVE) { + if (window_is_moving_) { + window_is_moving_ = false; + window_start_move_sent_ = false; + _EmitEvent("onWindowEndMove"); + } + } + + return result; + } + + PlatformUtil::~PlatformUtil() + { + debugLog("dealloc PlatformUtil"); + plugin = nullptr; + } +} diff --git a/flutter_inappwebview_windows/windows/platform_util.h b/flutter_inappwebview_windows/windows/platform_util.h new file mode 100644 index 000000000..75b5d795b --- /dev/null +++ b/flutter_inappwebview_windows/windows/platform_util.h @@ -0,0 +1,41 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_PLATFORM_UTIL_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_PLATFORM_UTIL_H_ + +#include +#include +#include +#include + +#include "flutter_inappwebview_windows_plugin.h" +#include "types/channel_delegate.h" + +namespace flutter_inappwebview_plugin +{ + class PlatformUtil : public ChannelDelegate + { + public: + static inline const std::string METHOD_CHANNEL_NAME_PREFIX = "com.pichillilorenzo/flutter_inappwebview_platformutil"; + + const FlutterInappwebviewWindowsPlugin* plugin; + + PlatformUtil(const FlutterInappwebviewWindowsPlugin* plugin); + ~PlatformUtil(); + + void HandleMethodCall( + const flutter::MethodCall& method_call, + std::unique_ptr> result); + + std::optional PlatformUtil::HandleWindowProc( + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam) noexcept; + + private: + void PlatformUtil::_EmitEvent(std::string eventName); + bool window_is_moving_ = false; + bool window_start_move_sent_ = false; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_PLATFORM_UTIL_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/plugin_scripts_js/javascript_bridge_js.cpp b/flutter_inappwebview_windows/windows/plugin_scripts_js/javascript_bridge_js.cpp deleted file mode 100644 index dcb743bf8..000000000 --- a/flutter_inappwebview_windows/windows/plugin_scripts_js/javascript_bridge_js.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include - -#include "javascript_bridge_js.h" - -namespace flutter_inappwebview_plugin -{ - std::unique_ptr createJavaScriptBridgePluginScript() - { - const std::vector allowedOriginRules = { "*" }; - return std::make_unique( - JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME, - JAVASCRIPT_BRIDGE_JS_SOURCE, - UserScriptInjectionTime::atDocumentStart, - allowedOriginRules, - nullptr, - true - ); - } -} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/plugin_scripts_js/javascript_bridge_js.h b/flutter_inappwebview_windows/windows/plugin_scripts_js/javascript_bridge_js.h index a10c832c4..8569113d5 100644 --- a/flutter_inappwebview_windows/windows/plugin_scripts_js/javascript_bridge_js.h +++ b/flutter_inappwebview_windows/windows/plugin_scripts_js/javascript_bridge_js.h @@ -5,27 +5,109 @@ #include #include "../types/plugin_script.h" +#include "../utils/log.h" +#include "../utils/string.h" namespace flutter_inappwebview_plugin { - const std::string JAVASCRIPT_BRIDGE_NAME = "flutter_inappwebview"; - const std::string JAVASCRIPT_BRIDGE_JS_SOURCE = "window." + JAVASCRIPT_BRIDGE_NAME + " = {}; \ - window." + JAVASCRIPT_BRIDGE_NAME + ".callHandler = function() { \ - var _callHandlerID = setTimeout(function() {}); \ - window.chrome.webview.postMessage({ 'name': 'callHandler', 'body': {'handlerName': arguments[0], '_callHandlerID' : _callHandlerID, 'args' : JSON.stringify(Array.prototype.slice.call(arguments, 1))} }); \ - return new Promise(function(resolve, reject) { \ - window." + JAVASCRIPT_BRIDGE_NAME + "[_callHandlerID] = { resolve: resolve, reject : reject };\ - });\ - };"; - const std::string JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT"; - const std::string PLATFORM_READY_JS_SOURCE = "(function() { \ - if ((window.top == null || window.top === window) && window." + JAVASCRIPT_BRIDGE_NAME + " != null && window." + JAVASCRIPT_BRIDGE_NAME + "._platformReady == null) { \ - window.dispatchEvent(new Event('flutterInAppWebViewPlatformReady')); \ - window." + JAVASCRIPT_BRIDGE_NAME + "._platformReady = true; \ - } \ - })();"; - - std::unique_ptr createJavaScriptBridgePluginScript(); + + class JavaScriptBridgeJS + { + public: + static void set_JAVASCRIPT_BRIDGE_NAME(const std::string& bridgeName) + { + _JAVASCRIPT_BRIDGE_NAME = bridgeName; + } + + static std::string get_JAVASCRIPT_BRIDGE_NAME() + { + return _JAVASCRIPT_BRIDGE_NAME; + } + + inline static const std::string JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT"; + + inline static const std::string VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET = "$IN_APP_WEBVIEW_JAVASCRIPT_BRIDGE_BRIDGE_SECRET"; + + static std::string JAVASCRIPT_BRIDGE_JS_SOURCE() + { + return "window." + get_JAVASCRIPT_BRIDGE_NAME() + " = {}; \ + (function(window) {\ + var bridgeSecret = '" + VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET + "';\ + var origin = '';\ + var requestUrl = '';\ + var isMainFrame = false;\ + var _JSON_stringify;\ + var _Array_slice;\ + var _setTimeout;\ + var _Promise;\ + var _postMessage;\ + try {\ + origin = window.location.origin;\ + } catch (_) {}\ + try {\ + requestUrl = window.location.href;\ + } catch (_) {}\ + try {\ + isMainFrame = window === window.top;\ + } catch (_) {}\ + try {\ + _JSON_stringify = window.JSON.stringify;\ + _Array_slice = window.Array.prototype.slice;\ + _Array_slice.call = window.Function.prototype.call;\ + _setTimeout = window.setTimeout;\ + _Promise = window.Promise;\ + _postMessage = window.chrome.webview.postMessage;\ + } catch (_) { return; }\ + window." + get_JAVASCRIPT_BRIDGE_NAME() + ".callHandler = function() { \ + try {\ + requestUrl = window.location.href;\ + } catch (_) {}\ + var _callHandlerID = _setTimeout(function() {}); \ + _postMessage({ 'name': 'callHandler', 'body': {\ + 'handlerName': arguments[0],\ + '_callHandlerID' : _callHandlerID,\ + '_bridgeSecret': bridgeSecret,\ + 'origin': origin,\ + 'requestUrl': requestUrl,\ + 'args' : _JSON_stringify(_Array_slice.call(arguments, 1))}\ + });\ + return new _Promise(function(resolve, reject) { \ + try {\ + (isMainFrame ? window : window.top)." + get_JAVASCRIPT_BRIDGE_NAME() + "[_callHandlerID] = { resolve: resolve, reject : reject };\ + } catch(e) { resolve(); }\ + });\ + };\ + })(window);"; + } + + static std::string PLATFORM_READY_JS_SOURCE() + { + return "(function() { \ + if ((window.top == null || window.top === window) && window." + get_JAVASCRIPT_BRIDGE_NAME() + " != null && window." + get_JAVASCRIPT_BRIDGE_NAME() + "._platformReady == null) { \ + window.dispatchEvent(new Event('flutterInAppWebViewPlatformReady')); \ + window." + get_JAVASCRIPT_BRIDGE_NAME() + "._platformReady = true; \ + } \ + })();"; + } + + static std::unique_ptr JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT(const std::string& expectedBridgeSecret, + const std::optional>& allowedOriginRules, const bool forMainFrameOnly) + { + auto source = replace_all_copy(JAVASCRIPT_BRIDGE_JS_SOURCE(), VAR_JAVASCRIPT_BRIDGE_BRIDGE_SECRET, expectedBridgeSecret); + return std::make_unique( + JAVASCRIPT_BRIDGE_JS_PLUGIN_SCRIPT_GROUP_NAME, + source, + UserScriptInjectionTime::atDocumentStart, + forMainFrameOnly, + allowedOriginRules, + nullptr, + true + ); + } + + private: + inline static std::string _JAVASCRIPT_BRIDGE_NAME = "flutter_inappwebview"; + }; } #endif //FLUTTER_INAPPWEBVIEW_PLUGIN_JAVASCRIPT_BRIDGE_JS_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/plugin_scripts_js/plugin_scripts_util.h b/flutter_inappwebview_windows/windows/plugin_scripts_js/plugin_scripts_util.h index 239783c3b..c5990505f 100644 --- a/flutter_inappwebview_windows/windows/plugin_scripts_js/plugin_scripts_util.h +++ b/flutter_inappwebview_windows/windows/plugin_scripts_js/plugin_scripts_util.h @@ -6,7 +6,6 @@ namespace flutter_inappwebview_plugin { const std::string VAR_PLACEHOLDER_VALUE = "$IN_APP_WEBVIEW_PLACEHOLDER_VALUE"; - const std::string VAR_PLACEHOLDER_MEMORY_ADDRESS_VALUE = "$IN_APP_WEBVIEW_PLACEHOLDER_MEMORY_ADDRESS_VALUE"; const std::string VAR_FUNCTION_ARGUMENT_NAMES = "$IN_APP_WEBVIEW_FUNCTION_ARGUMENT_NAMES"; const std::string VAR_FUNCTION_ARGUMENT_VALUES = "$IN_APP_WEBVIEW_FUNCTION_ARGUMENT_VALUES"; const std::string VAR_FUNCTION_BODY = "$IN_APP_WEBVIEW_FUNCTION_BODY"; diff --git a/flutter_inappwebview_windows/windows/types/accelerator_key_pressed_detail.cpp b/flutter_inappwebview_windows/windows/types/accelerator_key_pressed_detail.cpp new file mode 100644 index 000000000..dcb8da55c --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/accelerator_key_pressed_detail.cpp @@ -0,0 +1,34 @@ +#include "../utils/flutter.h" +#include "accelerator_key_pressed_detail.h" + +namespace flutter_inappwebview_plugin +{ + AcceleratorKeyPressedDetail::AcceleratorKeyPressedDetail(const std::optional& keyEventKind, + const std::optional> physicalKeyStatus, + const std::optional& virtualKey) + : keyEventKind(keyEventKind), physicalKeyStatus(physicalKeyStatus), virtualKey(virtualKey) + {} + + std::unique_ptr AcceleratorKeyPressedDetail::fromICoreWebView2AcceleratorKeyPressedEventArgs(const wil::com_ptr args) + { + COREWEBVIEW2_KEY_EVENT_KIND kind; + std::optional keyEventKind = SUCCEEDED(args->get_KeyEventKind(&kind)) ? (int64_t)kind : std::optional{}; + + COREWEBVIEW2_PHYSICAL_KEY_STATUS status; + std::optional> physicalKeyStatus = SUCCEEDED(args->get_PhysicalKeyStatus(&status)) ? PhysicalKeyStatus::fromCOREWEBVIEW2_PHYSICAL_KEY_STATUS(status) : std::optional>{}; + + UINT vKey; + std::optional virtualKey = SUCCEEDED(args->get_VirtualKey(&vKey)) ? (int64_t)vKey : std::optional{}; + + return std::make_unique(keyEventKind, physicalKeyStatus, virtualKey); + } + + flutter::EncodableMap AcceleratorKeyPressedDetail::toEncodableMap() const + { + return flutter::EncodableMap{ + { "keyEventKind", make_fl_value(keyEventKind) }, + { "physicalKeyStatus", physicalKeyStatus.has_value() ? make_fl_value(physicalKeyStatus.value()->toEncodableMap()) : make_fl_value() }, + { "virtualKey", make_fl_value(virtualKey) } + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/accelerator_key_pressed_detail.h b/flutter_inappwebview_windows/windows/types/accelerator_key_pressed_detail.h new file mode 100644 index 000000000..acf33a28f --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/accelerator_key_pressed_detail.h @@ -0,0 +1,31 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_ACCELERATOR_KEY_PRESSED_DETAIL_H +#define FLUTTER_INAPPWEBVIEW_PLUGIN_ACCELERATOR_KEY_PRESSED_DETAIL_H + +#include +#include +#include +#include + +#include "physical_key_status.h" + +namespace flutter_inappwebview_plugin +{ + class AcceleratorKeyPressedDetail + { + public: + const std::optional keyEventKind; + const std::optional> physicalKeyStatus; + const std::optional virtualKey; + + AcceleratorKeyPressedDetail(const std::optional& keyEventKind, + const std::optional> physicalKeyStatus, + const std::optional& virtualKey); + ~AcceleratorKeyPressedDetail() = default; + + static std::unique_ptr fromICoreWebView2AcceleratorKeyPressedEventArgs(const wil::com_ptr args); + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_ACCELERATOR_KEY_PRESSED_DETAIL_H \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/browser_process_exited_detail.cpp b/flutter_inappwebview_windows/windows/types/browser_process_exited_detail.cpp new file mode 100644 index 000000000..f92c58ea5 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/browser_process_exited_detail.cpp @@ -0,0 +1,17 @@ +#include "../utils/flutter.h" +#include "browser_process_exited_detail.h" + +namespace flutter_inappwebview_plugin +{ + BrowserProcessExitedDetail::BrowserProcessExitedDetail(const std::optional& kind, const std::optional& processId) + : kind(kind), processId(processId) + {} + + flutter::EncodableMap BrowserProcessExitedDetail::toEncodableMap() const + { + return flutter::EncodableMap{ + {"kind", make_fl_value(kind)}, + {"processId", make_fl_value(processId)} + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/browser_process_exited_detail.h b/flutter_inappwebview_windows/windows/types/browser_process_exited_detail.h new file mode 100644 index 000000000..158a92785 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/browser_process_exited_detail.h @@ -0,0 +1,23 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_BROWSER_PROCESS_EXITED_DETAIL_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_BROWSER_PROCESS_EXITED_DETAIL_H_ + +#include +#include + +namespace flutter_inappwebview_plugin +{ + class BrowserProcessExitedDetail + { + public: + const std::optional kind; + const std::optional processId; + + BrowserProcessExitedDetail(const std::optional& kind, + const std::optional& processId); + ~BrowserProcessExitedDetail() = default; + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_BROWSER_PROCESS_EXITED_DETAIL_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/browser_process_info.cpp b/flutter_inappwebview_windows/windows/types/browser_process_info.cpp new file mode 100644 index 000000000..dd78fe414 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/browser_process_info.cpp @@ -0,0 +1,62 @@ +#include "../utils/flutter.h" +#include "../utils/vector.h" +#include "browser_process_info.h" + +namespace flutter_inappwebview_plugin +{ + BrowserProcessInfo::BrowserProcessInfo(const std::optional& kind, const std::optional& processId, const std::optional>>& frameInfos) + : kind(kind), processId(processId), frameInfos(frameInfos) + {} + + std::unique_ptr BrowserProcessInfo::fromICoreWebView2ProcessInfo(const wil::com_ptr processInfo) + { + COREWEBVIEW2_PROCESS_KIND processKind; + std::optional kind = SUCCEEDED(processInfo->get_Kind(&processKind)) ? static_cast(processKind) : std::optional{}; + + INT32 pid; + std::optional processId = SUCCEEDED(processInfo->get_ProcessId(&pid)) ? static_cast(pid) : std::optional{}; + + const std::optional>> frameInfos = std::optional>>{}; + + return std::make_unique(kind, processId, frameInfos); + } + + std::unique_ptr BrowserProcessInfo::fromICoreWebView2ProcessExtendedInfo(const wil::com_ptr processExtendedInfo) + { + wil::com_ptr processInfo; + processExtendedInfo->get_ProcessInfo(&processInfo); + + COREWEBVIEW2_PROCESS_KIND processKind; + std::optional kind = processInfo && SUCCEEDED(processInfo->get_Kind(&processKind)) ? static_cast(processKind) : std::optional{}; + + INT32 pid; + std::optional processId = processInfo && SUCCEEDED(processInfo->get_ProcessId(&pid)) ? static_cast(pid) : std::optional{}; + + std::optional>> frameInfos = std::optional>>{}; + wil::com_ptr frameInfoCollection; + if (SUCCEEDED(processExtendedInfo->get_AssociatedFrameInfos(&frameInfoCollection))) { + wil::com_ptr iterator; + if (SUCCEEDED(frameInfoCollection->GetIterator(&iterator))) { + frameInfos = std::vector>{}; + BOOL hasCurrent = FALSE; + if (SUCCEEDED(iterator->get_HasCurrent(&hasCurrent)) && hasCurrent) { + wil::com_ptr frameInfo; + if (SUCCEEDED(iterator->GetCurrent(&frameInfo))) { + frameInfos.value().push_back(FrameInfo::fromICoreWebView2FrameInfo(frameInfo)); + } + } + } + } + + return std::make_unique(kind, processId, frameInfos); + } + + flutter::EncodableMap BrowserProcessInfo::toEncodableMap() const + { + return flutter::EncodableMap{ + {"kind", make_fl_value(kind)}, + {"processId", make_fl_value(processId)}, + {"frameInfos", frameInfos.has_value() ? make_fl_value(functional_map(frameInfos.value(), [](const std::shared_ptr& frameInfo) { return frameInfo->toEncodableMap(); })) : make_fl_value()} + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/browser_process_info.h b/flutter_inappwebview_windows/windows/types/browser_process_info.h new file mode 100644 index 000000000..56e20e31f --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/browser_process_info.h @@ -0,0 +1,32 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_BROWSER_PROCESS_INFO_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_BROWSER_PROCESS_INFO_H_ + +#include +#include +#include +#include + +#include "../types/frame_info.h" + +namespace flutter_inappwebview_plugin +{ + class BrowserProcessInfo + { + public: + const std::optional kind; + const std::optional processId; + const std::optional>> frameInfos; + + BrowserProcessInfo(const std::optional& kind, + const std::optional& processId, + const std::optional>>& frameInfos); + ~BrowserProcessInfo() = default; + + static std::unique_ptr fromICoreWebView2ProcessInfo(const wil::com_ptr processInfo); + static std::unique_ptr fromICoreWebView2ProcessExtendedInfo(const wil::com_ptr processExtendedInfo); + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_BROWSER_PROCESS_INFO_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/browser_process_infos_changed_detail.cpp b/flutter_inappwebview_windows/windows/types/browser_process_infos_changed_detail.cpp new file mode 100644 index 000000000..e6e3a9210 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/browser_process_infos_changed_detail.cpp @@ -0,0 +1,47 @@ +#include "../utils/flutter.h" +#include "../utils/vector.h" +#include "browser_process_infos_changed_detail.h" + +namespace flutter_inappwebview_plugin +{ + BrowserProcessInfosChangedDetail::BrowserProcessInfosChangedDetail(const std::vector>& infos) + : infos(infos) + {} + + std::unique_ptr BrowserProcessInfosChangedDetail::fromICoreWebView2ProcessInfoCollection(const wil::com_ptr processCollection) + { + std::vector> infos = {}; + UINT count; + if (SUCCEEDED(processCollection->get_Count(&count))) { + for (UINT i = 0; i < count; i++) { + wil::com_ptr processInfo; + if (SUCCEEDED(processCollection->GetValueAtIndex(i, &processInfo))) { + infos.push_back(BrowserProcessInfo::fromICoreWebView2ProcessInfo(processInfo)); + } + } + } + return std::make_unique(infos); + } + + std::unique_ptr BrowserProcessInfosChangedDetail::fromICoreWebView2ProcessExtendedInfoCollection(const wil::com_ptr processCollection) + { + std::vector> infos = {}; + UINT count; + if (SUCCEEDED(processCollection->get_Count(&count))) { + for (UINT i = 0; i < count; i++) { + wil::com_ptr processInfo; + if (SUCCEEDED(processCollection->GetValueAtIndex(i, &processInfo))) { + infos.push_back(BrowserProcessInfo::fromICoreWebView2ProcessExtendedInfo(processInfo)); + } + } + } + return std::make_unique(infos); + } + + flutter::EncodableMap BrowserProcessInfosChangedDetail::toEncodableMap() const + { + return flutter::EncodableMap{ + { "infos", make_fl_value(functional_map(infos, [](const std::shared_ptr& info) { return info->toEncodableMap(); })) } + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/browser_process_infos_changed_detail.h b/flutter_inappwebview_windows/windows/types/browser_process_infos_changed_detail.h new file mode 100644 index 000000000..225a552b3 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/browser_process_infos_changed_detail.h @@ -0,0 +1,25 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_BROWSER_PROCESS_INFOS_CHANGED_DETAIL_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_BROWSER_PROCESS_INFOS_CHANGED_DETAIL_H_ + +#include + +#include "browser_process_info.h" + +namespace flutter_inappwebview_plugin +{ + class BrowserProcessInfosChangedDetail + { + public: + const std::vector> infos; + + BrowserProcessInfosChangedDetail(const std::vector>& infos); + ~BrowserProcessInfosChangedDetail() = default; + + static std::unique_ptr fromICoreWebView2ProcessInfoCollection(const wil::com_ptr processCollection); + static std::unique_ptr fromICoreWebView2ProcessExtendedInfoCollection(const wil::com_ptr processCollection); + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_BROWSER_PROCESS_INFOS_CHANGED_DETAIL_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/channel_delegate.cpp b/flutter_inappwebview_windows/windows/types/channel_delegate.cpp index 983a2366f..b5db15048 100644 --- a/flutter_inappwebview_windows/windows/types/channel_delegate.cpp +++ b/flutter_inappwebview_windows/windows/types/channel_delegate.cpp @@ -24,12 +24,16 @@ namespace flutter_inappwebview_plugin std::unique_ptr> result) {} - ChannelDelegate::~ChannelDelegate() + void ChannelDelegate::UnregisterMethodCallHandler() const { - messenger = nullptr; - if (channel != nullptr) { + if (channel) { channel->SetMethodCallHandler(nullptr); } + } + + ChannelDelegate::~ChannelDelegate() + { + messenger = nullptr; channel.reset(); } } \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/channel_delegate.h b/flutter_inappwebview_windows/windows/types/channel_delegate.h index a412b7d10..5ccfdfa12 100644 --- a/flutter_inappwebview_windows/windows/types/channel_delegate.h +++ b/flutter_inappwebview_windows/windows/types/channel_delegate.h @@ -19,6 +19,8 @@ namespace flutter_inappwebview_plugin virtual void HandleMethodCall( const flutter::MethodCall& method_call, std::unique_ptr> result); + + void UnregisterMethodCallHandler() const; }; } diff --git a/flutter_inappwebview_windows/windows/types/client_cert_challenge.cpp b/flutter_inappwebview_windows/windows/types/client_cert_challenge.cpp new file mode 100644 index 000000000..f8359a8ee --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/client_cert_challenge.cpp @@ -0,0 +1,21 @@ +#include "../utils/flutter.h" +#include "client_cert_challenge.h" + +namespace flutter_inappwebview_plugin +{ + ClientCertChallenge::ClientCertChallenge(const std::shared_ptr protectionSpace, + const std::vector& allowedCertificateAuthorities, + const bool& isProxy, + const std::vector>& mutuallyTrustedCertificates) + : URLAuthenticationChallenge(protectionSpace), allowedCertificateAuthorities(allowedCertificateAuthorities), isProxy(isProxy), mutuallyTrustedCertificates(mutuallyTrustedCertificates) + {} + + flutter::EncodableMap ClientCertChallenge::toEncodableMap() const + { + auto map = URLAuthenticationChallenge::toEncodableMap(); + map.insert({ "allowedCertificateAuthorities", make_fl_value(allowedCertificateAuthorities) }); + map.insert({ "isProxy", make_fl_value(isProxy) }); + map.insert({ "mutuallyTrustedCertificates", make_fl_value(functional_map(mutuallyTrustedCertificates, [](const std::shared_ptr& item) { return item->toEncodableMap(); })) }); + return map; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/client_cert_challenge.h b/flutter_inappwebview_windows/windows/types/client_cert_challenge.h new file mode 100644 index 000000000..4f3a4c0ac --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/client_cert_challenge.h @@ -0,0 +1,29 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_CLIENT_CERT_CHALLENGE_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_CLIENT_CERT_CHALLENGE_H_ + +#include +#include +#include + +#include "url_authentication_challenge.h" + +namespace flutter_inappwebview_plugin +{ + class ClientCertChallenge : URLAuthenticationChallenge + { + public: + const std::vector allowedCertificateAuthorities; + const bool isProxy; + const std::vector> mutuallyTrustedCertificates; + + ClientCertChallenge(const std::shared_ptr protectionSpace, + const std::vector& allowedCertificateAuthorities, + const bool& isProxy, + const std::vector>& mutuallyTrustedCertificates); + ~ClientCertChallenge() = default; + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_CLIENT_CERT_CHALLENGE_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/client_cert_response.cpp b/flutter_inappwebview_windows/windows/types/client_cert_response.cpp new file mode 100644 index 000000000..ab33f5491 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/client_cert_response.cpp @@ -0,0 +1,23 @@ +#include "../utils/flutter.h" +#include "client_cert_response.h" + +namespace flutter_inappwebview_plugin +{ + ClientCertResponse::ClientCertResponse(const int64_t& selectedCertificate, + const std::optional& action) + : selectedCertificate(selectedCertificate), action(action) + {} + + ClientCertResponse::ClientCertResponse(const flutter::EncodableMap& map) + : ClientCertResponse(get_fl_map_value(map, "selectedCertificate"), + ClientCertResponseActionFromInteger(get_optional_fl_map_value(map, "action"))) + {} + + flutter::EncodableMap ClientCertResponse::toEncodableMap() const + { + return flutter::EncodableMap{ + {"selectedCertificate", make_fl_value(selectedCertificate)}, + {"action", make_fl_value(ClientCertResponseActionToInteger(action))} + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/client_cert_response.h b/flutter_inappwebview_windows/windows/types/client_cert_response.h new file mode 100644 index 000000000..bdd9586fd --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/client_cert_response.h @@ -0,0 +1,63 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_CLIENT_CERT_RESPONSE_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_CLIENT_CERT_RESPONSE_H_ + +#include +#include +#include + +namespace flutter_inappwebview_plugin +{ + enum class ClientCertResponseAction { + cancel = 0, + proceed, + ignore + }; + + inline ClientCertResponseAction ClientCertResponseActionFromInteger(const std::optional& action) + { + if (!action.has_value()) { + return ClientCertResponseAction::cancel; + } + switch (action.value()) { + case 0: + return ClientCertResponseAction::cancel; + case 1: + return ClientCertResponseAction::proceed; + case 2: + return ClientCertResponseAction::ignore; + default: + return ClientCertResponseAction::cancel; + } + } + + inline std::optional ClientCertResponseActionToInteger(const std::optional& action) + { + return action.has_value() ? static_cast(action.value()) : std::optional{}; + } + + class ClientCertResponse + { + public: + const int64_t selectedCertificate; + const std::optional action; + + ClientCertResponse(const int64_t& selectedCertificate, + const std::optional& action); + ClientCertResponse(const flutter::EncodableMap& map); + ~ClientCertResponse() = default; + + bool ClientCertResponse::operator==(const ClientCertResponse& other) + { + return selectedCertificate == other.selectedCertificate && + action == other.action; + } + bool ClientCertResponse::operator!=(const ClientCertResponse& other) + { + return !(*this == other); + } + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_CLIENT_CERT_RESPONSE_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/content_world.cpp b/flutter_inappwebview_windows/windows/types/content_world.cpp index a95e773cf..1c9ec1fee 100644 --- a/flutter_inappwebview_windows/windows/types/content_world.cpp +++ b/flutter_inappwebview_windows/windows/types/content_world.cpp @@ -12,7 +12,7 @@ namespace flutter_inappwebview_plugin {} ContentWorld::ContentWorld(const flutter::EncodableMap& map) - : name(get_fl_map_value(map, "name")) + : ContentWorld(get_fl_map_value(map, "name")) {} bool ContentWorld::isSame(const ContentWorld& contentWorld) const diff --git a/flutter_inappwebview_windows/windows/types/custom_scheme_registration.cpp b/flutter_inappwebview_windows/windows/types/custom_scheme_registration.cpp index b3cd295cf..1a25945b3 100644 --- a/flutter_inappwebview_windows/windows/types/custom_scheme_registration.cpp +++ b/flutter_inappwebview_windows/windows/types/custom_scheme_registration.cpp @@ -10,10 +10,10 @@ namespace flutter_inappwebview_plugin {} CustomSchemeRegistration::CustomSchemeRegistration(const flutter::EncodableMap& map) - : scheme(get_fl_map_value(map, "scheme")), - allowedOrigins(get_optional_fl_map_value>(map, "allowedOrigins")), - treatAsSecure(get_optional_fl_map_value(map, "treatAsSecure")), - hasAuthorityComponent(get_optional_fl_map_value(map, "hasAuthorityComponent")) + : CustomSchemeRegistration(get_fl_map_value(map, "scheme"), + get_optional_fl_map_value>(map, "allowedOrigins"), + get_optional_fl_map_value(map, "treatAsSecure"), + get_optional_fl_map_value(map, "hasAuthorityComponent")) {} flutter::EncodableMap CustomSchemeRegistration::toEncodableMap() const diff --git a/flutter_inappwebview_windows/windows/types/custom_scheme_response.cpp b/flutter_inappwebview_windows/windows/types/custom_scheme_response.cpp index 848aa3917..0ef63dd56 100644 --- a/flutter_inappwebview_windows/windows/types/custom_scheme_response.cpp +++ b/flutter_inappwebview_windows/windows/types/custom_scheme_response.cpp @@ -11,9 +11,9 @@ namespace flutter_inappwebview_plugin {} CustomSchemeResponse::CustomSchemeResponse(const flutter::EncodableMap& map) - : data(get_fl_map_value>(map, "data")), - contentType(get_fl_map_value(map, "contentType")), - contentEncoding(get_fl_map_value(map, "contentEncoding")) + : CustomSchemeResponse(get_fl_map_value>(map, "data"), + get_fl_map_value(map, "contentType"), + get_fl_map_value(map, "contentEncoding")) {} flutter::EncodableMap CustomSchemeResponse::toEncodableMap() const diff --git a/flutter_inappwebview_windows/windows/types/download_start_request.cpp b/flutter_inappwebview_windows/windows/types/download_start_request.cpp new file mode 100644 index 000000000..b6da8377b --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/download_start_request.cpp @@ -0,0 +1,24 @@ +#include "../utils/flutter.h" +#include "download_start_request.h" + +namespace flutter_inappwebview_plugin +{ + DownloadStartRequest::DownloadStartRequest(const std::optional& contentDisposition, + const int64_t& contentLength, + const std::optional& mimeType, + const std::optional& suggestedFilename, + const std::string& url) + : contentDisposition(contentDisposition), contentLength(contentLength), mimeType(mimeType), suggestedFilename(suggestedFilename), url(url) + {} + + flutter::EncodableMap DownloadStartRequest::toEncodableMap() const + { + return flutter::EncodableMap{ + {"contentDisposition", make_fl_value(contentDisposition)}, + {"contentLength", make_fl_value(contentLength)}, + {"mimeType", make_fl_value(mimeType)}, + {"suggestedFilename", make_fl_value(suggestedFilename)}, + {"url", make_fl_value(url)} + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/download_start_request.h b/flutter_inappwebview_windows/windows/types/download_start_request.h new file mode 100644 index 000000000..08844e50c --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/download_start_request.h @@ -0,0 +1,30 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_DOWNLOAD_START_REQUEST_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_DOWNLOAD_START_REQUEST_H_ + +#include +#include +#include + +namespace flutter_inappwebview_plugin +{ + class DownloadStartRequest + { + public: + const std::optional contentDisposition; + const int64_t contentLength; + const std::optional mimeType; + const std::optional suggestedFilename; + const std::string url; + + DownloadStartRequest(const std::optional& contentDisposition, + const int64_t& contentLength, + const std::optional& mimeType, + const std::optional& suggestedFilename, + const std::string& url); + ~DownloadStartRequest() = default; + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_DOWNLOAD_START_REQUEST_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/download_start_response.cpp b/flutter_inappwebview_windows/windows/types/download_start_response.cpp new file mode 100644 index 000000000..03cce81ec --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/download_start_response.cpp @@ -0,0 +1,26 @@ +#include "../utils/flutter.h" +#include "download_start_response.h" + +namespace flutter_inappwebview_plugin +{ + DownloadStartResponse::DownloadStartResponse(const bool& handled, + const std::optional& action, + const std::optional& resultFilePath) + : handled(handled), action(action), resultFilePath(resultFilePath) + {} + + DownloadStartResponse::DownloadStartResponse(const flutter::EncodableMap& map) + : DownloadStartResponse(get_fl_map_value(map, "handled"), + DownloadStartResponseActionFromInteger(get_optional_fl_map_value(map, "action")), + get_optional_fl_map_value(map, "resultFilePath")) + {} + + flutter::EncodableMap DownloadStartResponse::toEncodableMap() const + { + return flutter::EncodableMap{ + {"handled", make_fl_value(handled)}, + {"action", make_fl_value(DownloadStartResponseActionToInteger(action))}, + {"resultFilePath", make_fl_value(resultFilePath)} + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/download_start_response.h b/flutter_inappwebview_windows/windows/types/download_start_response.h new file mode 100644 index 000000000..62e4a984a --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/download_start_response.h @@ -0,0 +1,60 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_DOWNLOAD_START_RESPONSE_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_DOWNLOAD_START_RESPONSE_H_ + +#include +#include +#include + +namespace flutter_inappwebview_plugin +{ + enum class DownloadStartResponseAction { + cancel = 0 + }; + + inline std::optional DownloadStartResponseActionFromInteger(const std::optional& action) + { + if (action.has_value()) { + switch (action.value()) { + case 0: + return DownloadStartResponseAction::cancel; + default: + return DownloadStartResponseAction::cancel; + } + } + return std::optional{}; + } + + inline std::optional DownloadStartResponseActionToInteger(const std::optional& action) + { + return action.has_value() ? static_cast(action.value()) : std::optional{}; + } + + class DownloadStartResponse + { + public: + const bool handled; + const std::optional action; + const std::optional resultFilePath; + + DownloadStartResponse(const bool& handled, + const std::optional& action, + const std::optional& resultFilePath); + DownloadStartResponse(const flutter::EncodableMap& map); + ~DownloadStartResponse() = default; + + bool DownloadStartResponse::operator==(const DownloadStartResponse& other) + { + return handled == other.handled && + action == other.action && + resultFilePath == other.resultFilePath; + } + bool DownloadStartResponse::operator!=(const DownloadStartResponse& other) + { + return !(*this == other); + } + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_DOWNLOAD_START_RESPONSE_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/frame_info.cpp b/flutter_inappwebview_windows/windows/types/frame_info.cpp new file mode 100644 index 000000000..7417a3a0d --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/frame_info.cpp @@ -0,0 +1,79 @@ +#include "../utils/flutter.h" +#include "../utils/log.h" +#include "../utils/strconv.h" +#include "frame_info.h" + +#include + +namespace flutter_inappwebview_plugin +{ + FrameInfo::FrameInfo(const bool& isMainFrame, + const std::optional> request, + const std::optional> securityOrigin, + const std::optional& name, + const std::optional& frameId, + const std::optional& kind) + : isMainFrame(isMainFrame), request(request), securityOrigin(securityOrigin), name(name), frameId(frameId), kind(kind) + {} + + flutter::EncodableMap FrameInfo::toEncodableMap() const + { + return flutter::EncodableMap{ + {"isMainFrame", make_fl_value(isMainFrame)}, + {"request", request.has_value() ? request.value()->toEncodableMap() : make_fl_value()}, + {"securityOrigin", securityOrigin.has_value() ? securityOrigin.value()->toEncodableMap() : make_fl_value()}, + {"name", make_fl_value(name)}, + {"frameId", make_fl_value(frameId)}, + {"kind", make_fl_value(kind)} + }; + } + + std::unique_ptr FrameInfo::fromICoreWebView2FrameInfo(const wil::com_ptr webViewFrameInfo) + { + wil::unique_cotaskmem_string url; + auto request = std::optional>{}; + auto securityOrigin = std::optional>{}; + if (succeededOrLog(webViewFrameInfo->get_Source(&url))) { + auto sourceUrl = wide_to_utf8(url.get()); + request = std::make_shared( + sourceUrl, + std::optional{}, + std::optional>{}, + std::optional>{} + ); + + if (!sourceUrl.empty()) { + try { + winrt::Windows::Foundation::Uri const uri{ url.get() }; + + securityOrigin = std::make_shared( + wide_to_utf8(uri.Host().c_str()), + uri.Port(), + wide_to_utf8(uri.SchemeName().c_str()) + ); + } + catch (winrt::hresult_error const& ex) { + debugLog(wide_to_utf8(ex.message().c_str())); + } + } + } + + auto webViewFrameInfo2 = webViewFrameInfo.try_query(); + + uint32_t frameId; + wil::unique_cotaskmem_string name; + COREWEBVIEW2_FRAME_KIND kind = COREWEBVIEW2_FRAME_KIND_UNKNOWN; + if (webViewFrameInfo2) { + failedLog(webViewFrameInfo2->get_FrameKind(&kind)); + } + + return std::make_unique( + webViewFrameInfo2 ? kind == COREWEBVIEW2_FRAME_KIND_MAIN_FRAME : false, + request, + securityOrigin, + succeededOrLog(webViewFrameInfo->get_Name(&name)) ? wide_to_utf8(name.get()) : std::optional{}, + webViewFrameInfo2 && succeededOrLog(webViewFrameInfo2->get_FrameId(&frameId)) ? frameId : std::optional{}, + webViewFrameInfo2 ? (int64_t)kind : std::optional{} + ); + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/frame_info.h b/flutter_inappwebview_windows/windows/types/frame_info.h new file mode 100644 index 000000000..103c30e1a --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/frame_info.h @@ -0,0 +1,39 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_FRAME_INFO_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_FRAME_INFO_H_ + +#include +#include +#include +#include +#include + +#include "security_origin.h" +#include "url_request.h" + +namespace flutter_inappwebview_plugin +{ + + class FrameInfo + { + public: + const bool isMainFrame; + const std::optional> request; + const std::optional> securityOrigin; + const std::optional name; + const std::optional frameId; + const std::optional kind; + + FrameInfo(const bool& isMainFrame, + const std::optional> request, + const std::optional> securityOrigin, + const std::optional& name, + const std::optional& frameId, + const std::optional& kind); + ~FrameInfo() = default; + + flutter::EncodableMap toEncodableMap() const; + static std::unique_ptr fromICoreWebView2FrameInfo(const wil::com_ptr webViewFrameInfo); + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_FRAME_INFO_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/http_auth_response.cpp b/flutter_inappwebview_windows/windows/types/http_auth_response.cpp new file mode 100644 index 000000000..672d02ab7 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/http_auth_response.cpp @@ -0,0 +1,29 @@ +#include "../utils/flutter.h" +#include "http_auth_response.h" + +namespace flutter_inappwebview_plugin +{ + HttpAuthResponse::HttpAuthResponse(const std::string& username, + const std::string& password, + const bool& permanentPersistence, + const std::optional& action) + : username(username), password(password), permanentPersistence(permanentPersistence), action(action) + {} + + HttpAuthResponse::HttpAuthResponse(const flutter::EncodableMap& map) + : HttpAuthResponse(get_fl_map_value(map, "username"), + get_fl_map_value(map, "password"), + get_fl_map_value(map, "permanentPersistence"), + HttpAuthResponseActionFromInteger(get_optional_fl_map_value(map, "action"))) + {} + + flutter::EncodableMap HttpAuthResponse::toEncodableMap() const + { + return flutter::EncodableMap{ + {"username", make_fl_value(username)}, + {"password", make_fl_value(password)}, + {"permanentPersistence", make_fl_value(permanentPersistence)}, + {"action", make_fl_value(HttpAuthResponseActionToInteger(action))} + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/http_auth_response.h b/flutter_inappwebview_windows/windows/types/http_auth_response.h new file mode 100644 index 000000000..f80ce57a5 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/http_auth_response.h @@ -0,0 +1,69 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_HTTP_AUTH_RESPONSE_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_HTTP_AUTH_RESPONSE_H_ + +#include +#include +#include + +namespace flutter_inappwebview_plugin +{ + enum class HttpAuthResponseAction { + cancel = 0, + proceed, + useSavedHttpAuthCredentials // not supported currently + }; + + inline HttpAuthResponseAction HttpAuthResponseActionFromInteger(const std::optional& action) + { + if (!action.has_value()) { + return HttpAuthResponseAction::cancel; + } + switch (action.value()) { + case 0: + return HttpAuthResponseAction::cancel; + case 1: + return HttpAuthResponseAction::proceed; + case 2: + // not supported currently + // return HttpAuthResponseAction::useSavedHttpAuthCredentials; + default: + return HttpAuthResponseAction::cancel; + } + } + + inline std::optional HttpAuthResponseActionToInteger(const std::optional& action) + { + return action.has_value() ? static_cast(action.value()) : std::optional{}; + } + + class HttpAuthResponse + { + public: + const std::string username; + const std::string password; + const bool permanentPersistence; + const std::optional action; + + HttpAuthResponse(const std::string& username, + const std::string& password, + const bool& permanentPersistence, + const std::optional& action); + HttpAuthResponse(const flutter::EncodableMap& map); + ~HttpAuthResponse() = default; + + bool HttpAuthResponse::operator==(const HttpAuthResponse& other) + { + return username == other.username && password == other.password && + permanentPersistence == other.permanentPersistence && + action == other.action; + } + bool HttpAuthResponse::operator!=(const HttpAuthResponse& other) + { + return !(*this == other); + } + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_HTTP_AUTH_RESPONSE_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/http_authentication_challenge.cpp b/flutter_inappwebview_windows/windows/types/http_authentication_challenge.cpp new file mode 100644 index 000000000..6687469dd --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/http_authentication_challenge.cpp @@ -0,0 +1,19 @@ +#include "../utils/flutter.h" +#include "http_authentication_challenge.h" + +namespace flutter_inappwebview_plugin +{ + HttpAuthenticationChallenge::HttpAuthenticationChallenge(const std::shared_ptr protectionSpace, + const int64_t& previousFailureCount, + const std::optional> proposedCredential) + : URLAuthenticationChallenge(protectionSpace), previousFailureCount(previousFailureCount), proposedCredential(proposedCredential) + {} + + flutter::EncodableMap HttpAuthenticationChallenge::toEncodableMap() const + { + auto map = URLAuthenticationChallenge::toEncodableMap(); + map.insert({ "previousFailureCount", make_fl_value(previousFailureCount) }); + map.insert({ "proposedCredential", proposedCredential.has_value() ? proposedCredential.value()->toEncodableMap() : make_fl_value() }); + return map; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/http_authentication_challenge.h b/flutter_inappwebview_windows/windows/types/http_authentication_challenge.h new file mode 100644 index 000000000..ff2a26506 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/http_authentication_challenge.h @@ -0,0 +1,27 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_HTTP_AUTHENTICATION_CHALLENGE_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_HTTP_AUTHENTICATION_CHALLENGE_H_ + +#include +#include + +#include "url_authentication_challenge.h" +#include "url_credential.h" + +namespace flutter_inappwebview_plugin +{ + class HttpAuthenticationChallenge : URLAuthenticationChallenge + { + public: + const int64_t previousFailureCount; + const std::optional> proposedCredential; + + HttpAuthenticationChallenge(const std::shared_ptr protectionSpace, + const int64_t& previousFailureCount, + const std::optional> proposedCredential); + ~HttpAuthenticationChallenge() = default; + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_HTTP_AUTHENTICATION_CHALLENGE_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/javascript_handler_function_data.cpp b/flutter_inappwebview_windows/windows/types/javascript_handler_function_data.cpp new file mode 100644 index 000000000..af1683e84 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/javascript_handler_function_data.cpp @@ -0,0 +1,27 @@ +#include "../utils/flutter.h" +#include "../utils/string.h" +#include "javascript_handler_function_data.h" + +namespace flutter_inappwebview_plugin +{ + JavaScriptHandlerFunctionData::JavaScriptHandlerFunctionData(const std::string& origin, const std::string& requestUrl, const bool& isMainFrame, const std::string& args) + : origin(origin), requestUrl(requestUrl), isMainFrame(isMainFrame), args(args) + {} + + JavaScriptHandlerFunctionData::JavaScriptHandlerFunctionData(const flutter::EncodableMap& map) + : JavaScriptHandlerFunctionData(get_fl_map_value(map, "origin"), + get_fl_map_value(map, "requestUrl"), + get_fl_map_value(map, "isMainFrame"), + get_fl_map_value(map, "args")) + {} + + flutter::EncodableMap JavaScriptHandlerFunctionData::toEncodableMap() const + { + return flutter::EncodableMap{ + {"origin", make_fl_value(origin)}, + {"requestUrl", make_fl_value(requestUrl)}, + {"isMainFrame", make_fl_value(isMainFrame)}, + {"args", make_fl_value(args)} + }; + } +} diff --git a/flutter_inappwebview_windows/windows/types/javascript_handler_function_data.h b/flutter_inappwebview_windows/windows/types/javascript_handler_function_data.h new file mode 100644 index 000000000..aa5a3f6b3 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/javascript_handler_function_data.h @@ -0,0 +1,25 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_JAVASCRIPT_HANDLER_FUNCTION_DATA_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_JAVASCRIPT_HANDLER_FUNCTION_DATA_H_ + +#include +#include + +namespace flutter_inappwebview_plugin +{ + class JavaScriptHandlerFunctionData + { + public: + const std::string origin; + const std::string requestUrl; + const bool isMainFrame; + const std::string args; + + JavaScriptHandlerFunctionData(const std::string& origin, const std::string& requestUrl, const bool& isMainFrame, const std::string& args); + JavaScriptHandlerFunctionData(const flutter::EncodableMap& map); + ~JavaScriptHandlerFunctionData() = default; + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_JAVASCRIPT_HANDLER_FUNCTION_DATA_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/navigation_action.cpp b/flutter_inappwebview_windows/windows/types/navigation_action.cpp index 543553e70..d8be38645 100644 --- a/flutter_inappwebview_windows/windows/types/navigation_action.cpp +++ b/flutter_inappwebview_windows/windows/types/navigation_action.cpp @@ -15,7 +15,7 @@ namespace flutter_inappwebview_plugin {"request", request->toEncodableMap()}, {"isForMainFrame", isForMainFrame}, {"isRedirect", make_fl_value(isRedirect)}, - {"navigationType", make_fl_value(navigationType)} + {"navigationType", make_fl_value(NavigationActionTypeToInteger(navigationType))} }; } } \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/navigation_action.h b/flutter_inappwebview_windows/windows/types/navigation_action.h index 886640bef..1dced9307 100644 --- a/flutter_inappwebview_windows/windows/types/navigation_action.h +++ b/flutter_inappwebview_windows/windows/types/navigation_action.h @@ -8,13 +8,18 @@ namespace flutter_inappwebview_plugin { - enum NavigationActionType { + enum class NavigationActionType { linkActivated = 0, backForward, reload, other }; + inline std::optional NavigationActionTypeToInteger(const std::optional& action) + { + return action.has_value() ? static_cast(action.value()) : std::optional{}; + } + class NavigationAction { public: diff --git a/flutter_inappwebview_windows/windows/types/permission_response.cpp b/flutter_inappwebview_windows/windows/types/permission_response.cpp index e05598223..b6b7d3dd0 100644 --- a/flutter_inappwebview_windows/windows/types/permission_response.cpp +++ b/flutter_inappwebview_windows/windows/types/permission_response.cpp @@ -7,15 +7,15 @@ namespace flutter_inappwebview_plugin {} PermissionResponse::PermissionResponse(const flutter::EncodableMap& map) - : resources(get_optional_fl_map_value>(map, "resources")), - action(PermissionResponseActionTypeFromInteger(get_optional_fl_map_value(map, "action"))) + : PermissionResponse(get_optional_fl_map_value>(map, "resources"), + PermissionResponseActionTypeFromInteger(get_optional_fl_map_value(map, "action"))) {} flutter::EncodableMap PermissionResponse::toEncodableMap() const { return flutter::EncodableMap{ {"resources", make_fl_value(resources)}, - {"action", make_fl_value(action)}, + {"action", make_fl_value(PermissionResponseActionTypeToInteger(action))}, }; } } \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/permission_response.h b/flutter_inappwebview_windows/windows/types/permission_response.h index e96783146..fd5cf7854 100644 --- a/flutter_inappwebview_windows/windows/types/permission_response.h +++ b/flutter_inappwebview_windows/windows/types/permission_response.h @@ -2,13 +2,12 @@ #define FLUTTER_INAPPWEBVIEW_PLUGIN_PERMISSION_RESPONSE_H_ #include -#include #include "../utils/flutter.h" namespace flutter_inappwebview_plugin { - enum PermissionResponseActionType { + enum class PermissionResponseActionType { deny = 0, grant, prompt @@ -30,6 +29,11 @@ namespace flutter_inappwebview_plugin } } + inline std::optional PermissionResponseActionTypeToInteger(const std::optional& action) + { + return action.has_value() ? static_cast(action.value()) : std::optional{}; + } + class PermissionResponse { public: diff --git a/flutter_inappwebview_windows/windows/types/physical_key_status.cpp b/flutter_inappwebview_windows/windows/types/physical_key_status.cpp new file mode 100644 index 000000000..5cbe2d072 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/physical_key_status.cpp @@ -0,0 +1,31 @@ +#include "../utils/flutter.h" +#include "physical_key_status.h" + +namespace flutter_inappwebview_plugin +{ + PhysicalKeyStatus::PhysicalKeyStatus(const int64_t& repeatCount, + const int64_t& scanCode, + const bool& isExtendedKey, + const bool& isMenuKeyDown, + const bool& wasKeyDown, + const bool& isKeyReleased) + : repeatCount(repeatCount), scanCode(scanCode), isExtendedKey(isExtendedKey), isMenuKeyDown(isMenuKeyDown), wasKeyDown(wasKeyDown), isKeyReleased(isKeyReleased) + {} + + std::unique_ptr PhysicalKeyStatus::fromCOREWEBVIEW2_PHYSICAL_KEY_STATUS(const COREWEBVIEW2_PHYSICAL_KEY_STATUS& status) + { + return std::make_unique(status.RepeatCount, status.ScanCode, status.IsExtendedKey, status.IsMenuKeyDown, status.WasKeyDown, status.IsKeyReleased); + } + + flutter::EncodableMap PhysicalKeyStatus::toEncodableMap() const + { + return flutter::EncodableMap{ + { "repeatCount", make_fl_value(repeatCount) }, + { "scanCode", make_fl_value(scanCode) }, + { "isExtendedKey", make_fl_value(isExtendedKey) }, + { "isMenuKeyDown", make_fl_value(isMenuKeyDown) }, + { "wasKeyDown", make_fl_value(wasKeyDown) }, + { "isKeyReleased", make_fl_value(isKeyReleased) } + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/physical_key_status.h b/flutter_inappwebview_windows/windows/types/physical_key_status.h new file mode 100644 index 000000000..51fbd33a8 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/physical_key_status.h @@ -0,0 +1,33 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_PHYSICAL_KEY_STATUS_H +#define FLUTTER_INAPPWEBVIEW_PLUGIN_PHYSICAL_KEY_STATUS_H + +#include +#include + +namespace flutter_inappwebview_plugin +{ + class PhysicalKeyStatus + { + public: + const int64_t repeatCount; + const int64_t scanCode; + const bool isExtendedKey; + const bool isMenuKeyDown; + const bool wasKeyDown; + const bool isKeyReleased; + + PhysicalKeyStatus(const int64_t& repeatCount, + const int64_t& scanCode, + const bool& isExtendedKey, + const bool& isMenuKeyDown, + const bool& wasKeyDown, + const bool& isKeyReleased); + ~PhysicalKeyStatus() = default; + + static std::unique_ptr fromCOREWEBVIEW2_PHYSICAL_KEY_STATUS(const COREWEBVIEW2_PHYSICAL_KEY_STATUS& status); + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_PHYSICAL_KEY_STATUS_H \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/plugin_script.cpp b/flutter_inappwebview_windows/windows/types/plugin_script.cpp index cc37467ae..a292255ae 100644 --- a/flutter_inappwebview_windows/windows/types/plugin_script.cpp +++ b/flutter_inappwebview_windows/windows/types/plugin_script.cpp @@ -6,20 +6,21 @@ namespace flutter_inappwebview_plugin const std::optional& groupName, const std::string& source, const UserScriptInjectionTime& injectionTime, - const std::vector& allowedOriginRules, + const bool& forMainFrameOnly, + const std::optional>& allowedOriginRules, std::shared_ptr contentWorld, const bool& requiredInAllContentWorlds - ) : UserScript(groupName, source, injectionTime, allowedOriginRules, std::move(contentWorld)), + ) : UserScript(groupName, source, injectionTime, forMainFrameOnly, allowedOriginRules, std::move(contentWorld)), requiredInAllContentWorlds_(requiredInAllContentWorlds) {} - std::shared_ptr PluginScript::copyAndSet(const std::shared_ptr cw) const { return std::make_unique( this->groupName, this->source, this->injectionTime, + this->forMainFrameOnly, this->allowedOriginRules, cw, this->requiredInAllContentWorlds_ diff --git a/flutter_inappwebview_windows/windows/types/plugin_script.h b/flutter_inappwebview_windows/windows/types/plugin_script.h index e2fae03fa..c8a6efe52 100644 --- a/flutter_inappwebview_windows/windows/types/plugin_script.h +++ b/flutter_inappwebview_windows/windows/types/plugin_script.h @@ -13,7 +13,8 @@ namespace flutter_inappwebview_plugin const std::optional& groupName, const std::string& source, const UserScriptInjectionTime& injectionTime, - const std::vector& allowedOriginRules, + const bool& forMainFrameOnly, + const std::optional>& allowedOriginRules, std::shared_ptr contentWorld, const bool& requiredInAllContentWorlds ); diff --git a/flutter_inappwebview_windows/windows/types/process_failed_detail.cpp b/flutter_inappwebview_windows/windows/types/process_failed_detail.cpp new file mode 100644 index 000000000..be305a661 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/process_failed_detail.cpp @@ -0,0 +1,26 @@ +#include "../utils/flutter.h" +#include "process_failed_detail.h" + +namespace flutter_inappwebview_plugin +{ + ProcessFailedDetail::ProcessFailedDetail(const int64_t& kind, + const std::optional& exitCode, + const std::optional& processDescription, + const std::optional& reason, + const std::optional& failureSourceModulePath, + const std::optional>>& frameInfos) + : kind(kind), exitCode(exitCode), processDescription(processDescription), reason(reason), failureSourceModulePath(failureSourceModulePath), frameInfos(frameInfos) + {} + + flutter::EncodableMap ProcessFailedDetail::toEncodableMap() const + { + return flutter::EncodableMap{ + {"kind", make_fl_value(kind)}, + {"exitCode", make_fl_value(exitCode)}, + {"processDescription", make_fl_value(processDescription)}, + {"reason", make_fl_value(reason)}, + {"failureSourceModulePath", make_fl_value(failureSourceModulePath)}, + {"frameInfos", frameInfos.has_value() ? make_fl_value(functional_map(frameInfos.value(), [](const std::shared_ptr& item) { return item->toEncodableMap(); })) : make_fl_value()} + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/process_failed_detail.h b/flutter_inappwebview_windows/windows/types/process_failed_detail.h new file mode 100644 index 000000000..555ae4f69 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/process_failed_detail.h @@ -0,0 +1,36 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_PROCESS_FAILED_DETAIL_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_PROCESS_FAILED_DETAIL_H_ + +#include +#include +#include +#include + +#include "frame_info.h" + +namespace flutter_inappwebview_plugin +{ + + class ProcessFailedDetail + { + public: + const int64_t kind; + const std::optional exitCode; + const std::optional processDescription; + const std::optional reason; + const std::optional failureSourceModulePath; + const std::optional>> frameInfos; + + ProcessFailedDetail(const int64_t& kind, + const std::optional& exitCode, + const std::optional& processDescription, + const std::optional& reason, + const std::optional& failureSourceModulePath, + const std::optional>>& frameInfos); + ~ProcessFailedDetail() = default; + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_PROCESS_FAILED_DETAIL_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/rect.cpp b/flutter_inappwebview_windows/windows/types/rect.cpp index a0a41ab03..38fd176a1 100644 --- a/flutter_inappwebview_windows/windows/types/rect.cpp +++ b/flutter_inappwebview_windows/windows/types/rect.cpp @@ -7,10 +7,10 @@ namespace flutter_inappwebview_plugin {} Rect::Rect(const flutter::EncodableMap& map) - : x(get_fl_map_value(map, "x")), - y(get_fl_map_value(map, "y")), - width(get_fl_map_value(map, "width")), - height(get_fl_map_value(map, "height")) + : Rect(get_fl_map_value(map, "x"), + get_fl_map_value(map, "y"), + get_fl_map_value(map, "width"), + get_fl_map_value(map, "height")) {} flutter::EncodableMap Rect::toEncodableMap() const diff --git a/flutter_inappwebview_windows/windows/types/render_process_gone_detail.cpp b/flutter_inappwebview_windows/windows/types/render_process_gone_detail.cpp new file mode 100644 index 000000000..8fbb1238a --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/render_process_gone_detail.cpp @@ -0,0 +1,16 @@ +#include "../utils/flutter.h" +#include "render_process_gone_detail.h" + +namespace flutter_inappwebview_plugin +{ + RenderProcessGoneDetail::RenderProcessGoneDetail(const bool& didCrash) + : didCrash(didCrash) + {} + + flutter::EncodableMap RenderProcessGoneDetail::toEncodableMap() const + { + return flutter::EncodableMap{ + {"didCrash", make_fl_value(didCrash)} + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/render_process_gone_detail.h b/flutter_inappwebview_windows/windows/types/render_process_gone_detail.h new file mode 100644 index 000000000..3e324c1ae --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/render_process_gone_detail.h @@ -0,0 +1,21 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_RENDER_PROCESS_GONE_DETAIL_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_RENDER_PROCESS_GONE_DETAIL_H_ + +#include + +namespace flutter_inappwebview_plugin +{ + + class RenderProcessGoneDetail + { + public: + const bool didCrash; + + RenderProcessGoneDetail(const bool& didCrash); + ~RenderProcessGoneDetail() = default; + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_RENDER_PROCESS_GONE_DETAIL_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/screenshot_configuration.cpp b/flutter_inappwebview_windows/windows/types/screenshot_configuration.cpp index 5e0f027ee..a8ac01fb7 100644 --- a/flutter_inappwebview_windows/windows/types/screenshot_configuration.cpp +++ b/flutter_inappwebview_windows/windows/types/screenshot_configuration.cpp @@ -39,9 +39,9 @@ namespace flutter_inappwebview_plugin {} ScreenshotConfiguration::ScreenshotConfiguration(const flutter::EncodableMap& map) - : compressFormat(CompressFormatFromString(get_fl_map_value(map, "compressFormat"))), - quality(get_fl_map_value(map, "quality")), - rect(fl_map_contains_not_null(map, "rect") ? std::make_shared(get_fl_map_value(map, "rect")) : std::optional>{}) + : ScreenshotConfiguration(CompressFormatFromString(get_fl_map_value(map, "compressFormat")), + get_fl_map_value(map, "quality"), + fl_map_contains_not_null(map, "rect") ? std::make_shared(get_fl_map_value(map, "rect")) : std::optional>{}) {} ScreenshotConfiguration::~ScreenshotConfiguration() {} diff --git a/flutter_inappwebview_windows/windows/types/screenshot_configuration.h b/flutter_inappwebview_windows/windows/types/screenshot_configuration.h index f05ee7f05..b090bac69 100644 --- a/flutter_inappwebview_windows/windows/types/screenshot_configuration.h +++ b/flutter_inappwebview_windows/windows/types/screenshot_configuration.h @@ -10,7 +10,7 @@ namespace flutter_inappwebview_plugin { - enum CompressFormat { + enum class CompressFormat { png, jpeg, webp diff --git a/flutter_inappwebview_windows/windows/types/security_origin.cpp b/flutter_inappwebview_windows/windows/types/security_origin.cpp new file mode 100644 index 000000000..bfd43a329 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/security_origin.cpp @@ -0,0 +1,18 @@ +#include "../utils/flutter.h" +#include "security_origin.h" + +namespace flutter_inappwebview_plugin +{ + SecurityOrigin::SecurityOrigin(const std::string& host, const int64_t& port, const std::string& protocol) + : host(host), port(port), protocol(protocol) + {} + + flutter::EncodableMap SecurityOrigin::toEncodableMap() const + { + return flutter::EncodableMap{ + {"host", make_fl_value(host)}, + {"port", make_fl_value(port)}, + {"protocol", make_fl_value(protocol)} + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/security_origin.h b/flutter_inappwebview_windows/windows/types/security_origin.h new file mode 100644 index 000000000..84c3fee28 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/security_origin.h @@ -0,0 +1,24 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_SECURITY_ORIGIN_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_SECURITY_ORIGIN_H_ + +#include +#include + +namespace flutter_inappwebview_plugin +{ + + class SecurityOrigin + { + public: + const std::string host; + const int64_t port; + const std::string protocol; + + SecurityOrigin(const std::string& host, const int64_t& port, const std::string& protocol); + ~SecurityOrigin() = default; + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_SECURITY_ORIGIN_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/server_trust_auth_response.cpp b/flutter_inappwebview_windows/windows/types/server_trust_auth_response.cpp new file mode 100644 index 000000000..e502c0a9e --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/server_trust_auth_response.cpp @@ -0,0 +1,22 @@ +#include "../utils/flutter.h" +#include "server_trust_auth_response.h" + +namespace flutter_inappwebview_plugin +{ + ServerTrustAuthResponse::ServerTrustAuthResponse( + const std::optional& action) + : action(action) + {} + + ServerTrustAuthResponse::ServerTrustAuthResponse(const flutter::EncodableMap& map) + : ServerTrustAuthResponse( + ServerTrustAuthResponseActionFromInteger(get_optional_fl_map_value(map, "action"))) + {} + + flutter::EncodableMap ServerTrustAuthResponse::toEncodableMap() const + { + return flutter::EncodableMap{ + {"action", make_fl_value(ServerTrustAuthResponseActionToInteger(action))} + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/server_trust_auth_response.h b/flutter_inappwebview_windows/windows/types/server_trust_auth_response.h new file mode 100644 index 000000000..af2c7ba2e --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/server_trust_auth_response.h @@ -0,0 +1,55 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_SERVER_TRUST_AUTH_RESPONSE_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_SERVER_TRUST_AUTH_RESPONSE_H_ + +#include +#include + +namespace flutter_inappwebview_plugin +{ + enum class ServerTrustAuthResponseAction { + cancel = 0, + proceed + }; + + inline ServerTrustAuthResponseAction ServerTrustAuthResponseActionFromInteger(const std::optional& action) + { + if (!action.has_value()) { + return ServerTrustAuthResponseAction::cancel; + } + switch (action.value()) { + case 1: + return ServerTrustAuthResponseAction::proceed; + case 0: + default: + return ServerTrustAuthResponseAction::cancel; + } + } + + inline std::optional ServerTrustAuthResponseActionToInteger(const std::optional& action) + { + return action.has_value() ? static_cast(action.value()) : std::optional{}; + } + + class ServerTrustAuthResponse + { + public: + const std::optional action; + + ServerTrustAuthResponse(const std::optional& action); + ServerTrustAuthResponse(const flutter::EncodableMap& map); + ~ServerTrustAuthResponse() = default; + + bool ServerTrustAuthResponse::operator==(const ServerTrustAuthResponse& other) + { + return action == other.action; + } + bool ServerTrustAuthResponse::operator!=(const ServerTrustAuthResponse& other) + { + return !(*this == other); + } + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_SERVER_TRUST_AUTH_RESPONSE_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/server_trust_challenge.cpp b/flutter_inappwebview_windows/windows/types/server_trust_challenge.cpp new file mode 100644 index 000000000..d20c8c285 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/server_trust_challenge.cpp @@ -0,0 +1,15 @@ +#include "../utils/flutter.h" +#include "server_trust_challenge.h" + +namespace flutter_inappwebview_plugin +{ + ServerTrustChallenge::ServerTrustChallenge(const std::shared_ptr protectionSpace) + : URLAuthenticationChallenge(protectionSpace) + {} + + flutter::EncodableMap ServerTrustChallenge::toEncodableMap() const + { + auto map = URLAuthenticationChallenge::toEncodableMap(); + return map; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/server_trust_challenge.h b/flutter_inappwebview_windows/windows/types/server_trust_challenge.h new file mode 100644 index 000000000..9121ec800 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/server_trust_challenge.h @@ -0,0 +1,21 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_SERVER_TRUST_CHALLENGE_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_SERVER_TRUST_CHALLENGE_H_ + +#include +#include + +#include "url_authentication_challenge.h" + +namespace flutter_inappwebview_plugin +{ + class ServerTrustChallenge : URLAuthenticationChallenge + { + public: + ServerTrustChallenge(const std::shared_ptr protectionSpace); + ~ServerTrustChallenge() = default; + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_SERVER_TRUST_CHALLENGE_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/size_2d.cpp b/flutter_inappwebview_windows/windows/types/size_2d.cpp index e12390266..7a790854d 100644 --- a/flutter_inappwebview_windows/windows/types/size_2d.cpp +++ b/flutter_inappwebview_windows/windows/types/size_2d.cpp @@ -2,13 +2,13 @@ namespace flutter_inappwebview_plugin { - Size2D::Size2D(const double& width, const double& height) + Size2D::Size2D(const double& width, const double& height) : width(width), height(height) {} - Size2D::Size2D(const flutter::EncodableMap& map) - : width(get_fl_map_value(map, "width")), - height(get_fl_map_value(map, "height")) + Size2D::Size2D(const flutter::EncodableMap& map) + : Size2D(get_fl_map_value(map, "width"), + get_fl_map_value(map, "height")) {} flutter::EncodableMap Size2D::toEncodableMap() const diff --git a/flutter_inappwebview_windows/windows/types/ssl_error.cpp b/flutter_inappwebview_windows/windows/types/ssl_error.cpp new file mode 100644 index 000000000..1147862d0 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/ssl_error.cpp @@ -0,0 +1,17 @@ +#include "../utils/flutter.h" +#include "ssl_error.h" + +namespace flutter_inappwebview_plugin +{ + SslError::SslError(const COREWEBVIEW2_WEB_ERROR_STATUS& code, const std::optional& message) + : code(code), message(message) + {} + + flutter::EncodableMap SslError::toEncodableMap() const + { + return flutter::EncodableMap{ + {"code", make_fl_value((int64_t)code)}, + {"message", make_fl_value(message)} + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/ssl_error.h b/flutter_inappwebview_windows/windows/types/ssl_error.h new file mode 100644 index 000000000..a86204577 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/ssl_error.h @@ -0,0 +1,44 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_SSL_ERROR_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_SSL_ERROR_H_ + +#include +#include +#include + +#include "WebView2.h" + +namespace flutter_inappwebview_plugin +{ + inline std::optional COREWEBVIEW2_WEB_ERROR_STATUS_ToString(const COREWEBVIEW2_WEB_ERROR_STATUS& code) + { + switch (code) { + case COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_COMMON_NAME_IS_INCORRECT: + return "Indicates that the SSL certificate common name does not match the web address."; + case COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_EXPIRED: + return "Indicates that the SSL certificate has expired."; + case COREWEBVIEW2_WEB_ERROR_STATUS_CLIENT_CERTIFICATE_CONTAINS_ERRORS: + return "Indicates that the SSL client certificate contains errors."; + case COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_REVOKED: + return "Indicates that the SSL certificate has been revoked."; + case COREWEBVIEW2_WEB_ERROR_STATUS_CERTIFICATE_IS_INVALID: + return "Indicates that the SSL certificate is not valid."; + default: + break; + } + return std::optional{}; + } + + class SslError + { + public: + const COREWEBVIEW2_WEB_ERROR_STATUS code; + const std::optional message; + + SslError(const COREWEBVIEW2_WEB_ERROR_STATUS& code, const std::optional& message); + ~SslError() = default; + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_SSL_ERROR_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/url_authentication_challenge.cpp b/flutter_inappwebview_windows/windows/types/url_authentication_challenge.cpp new file mode 100644 index 000000000..7b1a5ff72 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/url_authentication_challenge.cpp @@ -0,0 +1,16 @@ +#include "../utils/flutter.h" +#include "url_authentication_challenge.h" + +namespace flutter_inappwebview_plugin +{ + URLAuthenticationChallenge::URLAuthenticationChallenge(const std::shared_ptr protectionSpace) + : protectionSpace(protectionSpace) + {} + + flutter::EncodableMap URLAuthenticationChallenge::toEncodableMap() const + { + return flutter::EncodableMap{ + {"protectionSpace", protectionSpace->toEncodableMap()}, + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/url_authentication_challenge.h b/flutter_inappwebview_windows/windows/types/url_authentication_challenge.h new file mode 100644 index 000000000..80688107f --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/url_authentication_challenge.h @@ -0,0 +1,22 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_URL_AUTHENTICATION_CHALLENGE_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_URL_AUTHENTICATION_CHALLENGE_H_ + +#include + +#include "url_protection_space.h" + +namespace flutter_inappwebview_plugin +{ + class URLAuthenticationChallenge + { + public: + const std::shared_ptr protectionSpace; + + URLAuthenticationChallenge(const std::shared_ptr protectionSpace); + ~URLAuthenticationChallenge() = default; + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_URL_AUTHENTICATION_CHALLENGE_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/url_credential.cpp b/flutter_inappwebview_windows/windows/types/url_credential.cpp new file mode 100644 index 000000000..f02c7565d --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/url_credential.cpp @@ -0,0 +1,18 @@ +#include "../utils/flutter.h" +#include "url_credential.h" + +namespace flutter_inappwebview_plugin +{ + URLCredential::URLCredential(const std::optional& username, + const std::optional& password) + : username(username), password(password) + {} + + flutter::EncodableMap URLCredential::toEncodableMap() const + { + return flutter::EncodableMap{ + {"username", make_fl_value(username)}, + {"password", make_fl_value(password)} + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/url_credential.h b/flutter_inappwebview_windows/windows/types/url_credential.h new file mode 100644 index 000000000..2f40bb7d4 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/url_credential.h @@ -0,0 +1,24 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_URL_CREDENTIAL_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_URL_CREDENTIAL_H_ + +#include +#include +#include + +namespace flutter_inappwebview_plugin +{ + class URLCredential + { + public: + const std::optional username; + const std::optional password; + + URLCredential(const std::optional& username, + const std::optional& password); + ~URLCredential() = default; + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_URL_CREDENTIAL_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/url_protection_space.cpp b/flutter_inappwebview_windows/windows/types/url_protection_space.cpp new file mode 100644 index 000000000..26d62af97 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/url_protection_space.cpp @@ -0,0 +1,24 @@ +#include "../utils/flutter.h" +#include "url_protection_space.h" + +namespace flutter_inappwebview_plugin +{ + URLProtectionSpace::URLProtectionSpace(const std::string& host, const std::string& protocol, + const std::optional& realm, const int64_t& port, + const std::optional> sslCertificate, + const std::optional> sslError) + : host(host), protocol(protocol), realm(realm), port(port), sslCertificate(sslCertificate), sslError(sslError) + {} + + flutter::EncodableMap URLProtectionSpace::toEncodableMap() const + { + return flutter::EncodableMap{ + {"host", make_fl_value(host)}, + {"protocol", make_fl_value(protocol)}, + {"realm", make_fl_value(realm)}, + {"port", make_fl_value(port)}, + {"sslCertificate", sslCertificate.has_value() ? sslCertificate.value()->toEncodableMap() : make_fl_value()}, + {"sslError", sslError.has_value() ? sslError.value()->toEncodableMap() : make_fl_value()}, + }; + } +} \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/url_protection_space.h b/flutter_inappwebview_windows/windows/types/url_protection_space.h new file mode 100644 index 000000000..44265c0b6 --- /dev/null +++ b/flutter_inappwebview_windows/windows/types/url_protection_space.h @@ -0,0 +1,33 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_URL_PROTECTION_SPACE_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_URL_PROTECTION_SPACE_H_ + +#include +#include +#include + +#include "ssl_certificate.h" +#include "ssl_error.h" + +namespace flutter_inappwebview_plugin +{ + class URLProtectionSpace + { + public: + const std::string host; + const std::string protocol; + const std::optional realm; + const int64_t port; + const std::optional> sslCertificate; + const std::optional> sslError; + + URLProtectionSpace(const std::string& host, const std::string& protocol, + const std::optional& realm, const int64_t& port, + const std::optional> sslCertificate, + const std::optional> sslError); + ~URLProtectionSpace() = default; + + flutter::EncodableMap toEncodableMap() const; + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_URL_PROTECTION_SPACE_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/types/url_request.cpp b/flutter_inappwebview_windows/windows/types/url_request.cpp index 42340dd08..7335b0bd7 100644 --- a/flutter_inappwebview_windows/windows/types/url_request.cpp +++ b/flutter_inappwebview_windows/windows/types/url_request.cpp @@ -9,10 +9,10 @@ namespace flutter_inappwebview_plugin {} URLRequest::URLRequest(const flutter::EncodableMap& map) - : url(get_optional_fl_map_value(map, "url")), - method(get_optional_fl_map_value(map, "method")), - headers(get_optional_fl_map_value>(map, "headers")), - body(get_optional_fl_map_value>(map, "body")) + : URLRequest(get_optional_fl_map_value(map, "url"), + get_optional_fl_map_value(map, "method"), + get_optional_fl_map_value>(map, "headers"), + get_optional_fl_map_value>(map, "body")) {} flutter::EncodableMap URLRequest::toEncodableMap() const diff --git a/flutter_inappwebview_windows/windows/types/user_script.cpp b/flutter_inappwebview_windows/windows/types/user_script.cpp index 6a783fe08..c74d705b3 100644 --- a/flutter_inappwebview_windows/windows/types/user_script.cpp +++ b/flutter_inappwebview_windows/windows/types/user_script.cpp @@ -1,25 +1,32 @@ -#include "../utils/map.h" #include "user_script.h" +#include "../utils/log.h" +#include "../utils/string.h" + namespace flutter_inappwebview_plugin { UserScript::UserScript( const std::optional& groupName, const std::string& source, const UserScriptInjectionTime& injectionTime, - const std::vector& allowedOriginRules, + const bool& forMainFrameOnly, + const std::optional>& allowedOriginRules, std::shared_ptr contentWorld - ) : groupName(groupName), source(source), injectionTime(injectionTime), allowedOriginRules(allowedOriginRules), contentWorld(std::move(contentWorld)) + ) : groupName(groupName), source(source), + injectionTime(injectionTime), forMainFrameOnly(forMainFrameOnly), allowedOriginRules(allowedOriginRules), contentWorld(std::move(contentWorld)) {} UserScript::UserScript(const flutter::EncodableMap& map) - : groupName(get_optional_fl_map_value(map, "groupName")), - source(get_fl_map_value(map, "source")), - injectionTime(static_cast(get_fl_map_value(map, "injectionTime"))), - allowedOriginRules(functional_map(get_fl_map_value(map, "allowedOriginRules"), [](const flutter::EncodableValue& m) { return std::get(m); })), - contentWorld(std::make_shared(get_fl_map_value(map, "contentWorld"))) + : UserScript(get_optional_fl_map_value(map, "groupName"), + get_fl_map_value(map, "source"), + static_cast(get_fl_map_value(map, "injectionTime")), + get_fl_map_value(map, "forMainFrameOnly"), + fl_map_contains_not_null(map, "allowedOriginRules") ? + functional_map(get_fl_map_value(map, "allowedOriginRules"), [](const flutter::EncodableValue& m) { return std::get(m); }) + : std::optional>{}, + std::make_shared(get_fl_map_value(map, "contentWorld"))) {} UserScript::~UserScript() {} -} \ No newline at end of file +} diff --git a/flutter_inappwebview_windows/windows/types/user_script.h b/flutter_inappwebview_windows/windows/types/user_script.h index 473661f0e..1ea9d472d 100644 --- a/flutter_inappwebview_windows/windows/types/user_script.h +++ b/flutter_inappwebview_windows/windows/types/user_script.h @@ -11,7 +11,7 @@ namespace flutter_inappwebview_plugin { - enum UserScriptInjectionTime { + enum class UserScriptInjectionTime { atDocumentStart = 0, atDocumentEnd }; @@ -23,14 +23,16 @@ namespace flutter_inappwebview_plugin const std::optional groupName; const std::string source; const UserScriptInjectionTime injectionTime; - const std::vector allowedOriginRules; + const bool forMainFrameOnly; + const std::optional> allowedOriginRules; const std::shared_ptr contentWorld; UserScript( const std::optional& groupName, const std::string& source, const UserScriptInjectionTime& injectionTime, - const std::vector& allowedOriginRules, + const bool& forMainFrameOnly, + const std::optional>& allowedOriginRules, std::shared_ptr contentWorld ); UserScript(const flutter::EncodableMap& map); diff --git a/flutter_inappwebview_windows/windows/types/web_history.cpp b/flutter_inappwebview_windows/windows/types/web_history.cpp index aa89d9a2d..1790b61f7 100644 --- a/flutter_inappwebview_windows/windows/types/web_history.cpp +++ b/flutter_inappwebview_windows/windows/types/web_history.cpp @@ -8,8 +8,8 @@ namespace flutter_inappwebview_plugin {} WebHistory::WebHistory(const flutter::EncodableMap& map) - : currentIndex(get_optional_fl_map_value(map, "currentIndex")), - list(functional_map(get_optional_fl_map_value(map, "list"), [](const flutter::EncodableValue& m) { return std::make_shared(std::get(m)); })) + : WebHistory(get_optional_fl_map_value(map, "currentIndex"), + functional_map(get_optional_fl_map_value(map, "list"), [](const flutter::EncodableValue& m) { return std::make_shared(std::get(m)); })) {} flutter::EncodableMap WebHistory::toEncodableMap() const diff --git a/flutter_inappwebview_windows/windows/types/web_history_item.cpp b/flutter_inappwebview_windows/windows/types/web_history_item.cpp index 11350eebb..d2849df82 100644 --- a/flutter_inappwebview_windows/windows/types/web_history_item.cpp +++ b/flutter_inappwebview_windows/windows/types/web_history_item.cpp @@ -9,12 +9,12 @@ namespace flutter_inappwebview_plugin {} WebHistoryItem::WebHistoryItem(const flutter::EncodableMap& map) - : entryId(get_optional_fl_map_value(map, "entryId")), - index(get_optional_fl_map_value(map, "index")), - offset(get_optional_fl_map_value(map, "offset")), - originalUrl(get_optional_fl_map_value(map, "originalUrl")), - title(get_optional_fl_map_value(map, "title")), - url(get_optional_fl_map_value(map, "url")) + : WebHistoryItem(get_optional_fl_map_value(map, "entryId"), + get_optional_fl_map_value(map, "index"), + get_optional_fl_map_value(map, "offset"), + get_optional_fl_map_value(map, "originalUrl"), + get_optional_fl_map_value(map, "title"), + get_optional_fl_map_value(map, "url")) {} flutter::EncodableMap WebHistoryItem::toEncodableMap() const diff --git a/flutter_inappwebview_windows/windows/types/web_resource_error.cpp b/flutter_inappwebview_windows/windows/types/web_resource_error.cpp index 5059a3dcf..5f674d597 100644 --- a/flutter_inappwebview_windows/windows/types/web_resource_error.cpp +++ b/flutter_inappwebview_windows/windows/types/web_resource_error.cpp @@ -8,8 +8,8 @@ namespace flutter_inappwebview_plugin {} WebResourceError::WebResourceError(const flutter::EncodableMap& map) - : description(get_fl_map_value(map, "description")), - type(get_fl_map_value(map, "type")) + : WebResourceError(get_fl_map_value(map, "description"), + get_fl_map_value(map, "type")) {} flutter::EncodableMap WebResourceError::toEncodableMap() const diff --git a/flutter_inappwebview_windows/windows/types/web_resource_request.cpp b/flutter_inappwebview_windows/windows/types/web_resource_request.cpp index 437fa1903..42896c204 100644 --- a/flutter_inappwebview_windows/windows/types/web_resource_request.cpp +++ b/flutter_inappwebview_windows/windows/types/web_resource_request.cpp @@ -10,10 +10,10 @@ namespace flutter_inappwebview_plugin {} WebResourceRequest::WebResourceRequest(const flutter::EncodableMap& map) - : url(get_optional_fl_map_value(map, "url")), - method(get_optional_fl_map_value(map, "method")), - headers(get_optional_fl_map_value>(map, "headers")), - isForMainFrame(get_optional_fl_map_value(map, "isForMainFrame")) + : WebResourceRequest(get_optional_fl_map_value(map, "url"), + get_optional_fl_map_value(map, "method"), + get_optional_fl_map_value>(map, "headers"), + get_optional_fl_map_value(map, "isForMainFrame")) {} WebResourceRequest::WebResourceRequest(wil::com_ptr webResourceRequest) diff --git a/flutter_inappwebview_windows/windows/types/web_resource_response.cpp b/flutter_inappwebview_windows/windows/types/web_resource_response.cpp index bd17832c6..430cf1afe 100644 --- a/flutter_inappwebview_windows/windows/types/web_resource_response.cpp +++ b/flutter_inappwebview_windows/windows/types/web_resource_response.cpp @@ -17,12 +17,12 @@ namespace flutter_inappwebview_plugin {} WebResourceResponse::WebResourceResponse(const flutter::EncodableMap& map) - : contentType(get_optional_fl_map_value(map, "contentType")), - contentEncoding(get_optional_fl_map_value(map, "contentEncoding")), - statusCode(get_optional_fl_map_value(map, "statusCode")), - reasonPhrase(get_optional_fl_map_value(map, "reasonPhrase")), - headers(get_optional_fl_map_value>(map, "headers")), - data(get_optional_fl_map_value>(map, "data")) + : WebResourceResponse(get_optional_fl_map_value(map, "contentType"), + get_optional_fl_map_value(map, "contentEncoding"), + get_optional_fl_map_value(map, "statusCode"), + get_optional_fl_map_value(map, "reasonPhrase"), + get_optional_fl_map_value>(map, "headers"), + get_optional_fl_map_value>(map, "data")) {} flutter::EncodableMap WebResourceResponse::toEncodableMap() const diff --git a/flutter_inappwebview_windows/windows/utils/base64.cpp b/flutter_inappwebview_windows/windows/utils/base64.cpp index 843719ec9..938caae36 100644 --- a/flutter_inappwebview_windows/windows/utils/base64.cpp +++ b/flutter_inappwebview_windows/windows/utils/base64.cpp @@ -36,11 +36,11 @@ #include #include - // - // Depending on the url parameter in base64_chars, one of - // two sets of base64 characters needs to be chosen. - // They differ in their last two characters. - // +// +// Depending on the url parameter in base64_chars, one of +// two sets of base64 characters needs to be chosen. +// They differ in their last two characters. +// static const char* base64_chars[2] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" @@ -50,147 +50,155 @@ static const char* base64_chars[2] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789" - "-_"}; - -static unsigned int pos_of_char(const unsigned char chr) { - // - // Return the position of chr within base64_encode() - // - - if (chr >= 'A' && chr <= 'Z') return chr - 'A'; - else if (chr >= 'a' && chr <= 'z') return chr - 'a' + ('Z' - 'A') + 1; - else if (chr >= '0' && chr <= '9') return chr - '0' + ('Z' - 'A') + ('z' - 'a') + 2; - else if (chr == '+' || chr == '-') return 62; // Be liberal with input and accept both url ('-') and non-url ('+') base 64 characters ( - else if (chr == '/' || chr == '_') return 63; // Ditto for '/' and '_' - else - // - // 2020-10-23: Throw std::exception rather than const char* - //(Pablo Martin-Gomez, https://github.com/Bouska) - // + "-_" }; + +static unsigned int pos_of_char(const unsigned char chr) +{ + // + // Return the position of chr within base64_encode() + // + + if (chr >= 'A' && chr <= 'Z') return chr - 'A'; + else if (chr >= 'a' && chr <= 'z') return chr - 'a' + ('Z' - 'A') + 1; + else if (chr >= '0' && chr <= '9') return chr - '0' + ('Z' - 'A') + ('z' - 'a') + 2; + else if (chr == '+' || chr == '-') return 62; // Be liberal with input and accept both url ('-') and non-url ('+') base 64 characters ( + else if (chr == '/' || chr == '_') return 63; // Ditto for '/' and '_' + else + // + // 2020-10-23: Throw std::exception rather than const char* + //(Pablo Martin-Gomez, https://github.com/Bouska) + // throw std::runtime_error("Input is not valid base64-encoded data."); } -static std::string insert_linebreaks(std::string str, size_t distance) { - // - // Provided by https://github.com/JomaCorpFX, adapted by me. - // - if (!str.length()) { - return ""; - } +static std::string insert_linebreaks(std::string str, size_t distance) +{ + // + // Provided by https://github.com/JomaCorpFX, adapted by me. + // + if (!str.length()) { + return ""; + } - size_t pos = distance; + size_t pos = distance; - while (pos < str.size()) { - str.insert(pos, "\n"); - pos += distance + 1; - } + while (pos < str.size()) { + str.insert(pos, "\n"); + pos += distance + 1; + } - return str; + return str; } template -static std::string encode_with_line_breaks(String s) { +static std::string encode_with_line_breaks(String s) +{ return insert_linebreaks(base64_encode(s, false), line_length); } template -static std::string encode_pem(String s) { +static std::string encode_pem(String s) +{ return encode_with_line_breaks(s); } template -static std::string encode_mime(String s) { +static std::string encode_mime(String s) +{ return encode_with_line_breaks(s); } template -static std::string encode(String s, bool url) { +static std::string encode(String s, bool url) +{ return base64_encode(reinterpret_cast(s.data()), s.length(), url); } -std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len, bool url) { +std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len, bool url) +{ - size_t len_encoded = (in_len +2) / 3 * 4; + size_t len_encoded = (in_len + 2) / 3 * 4; - unsigned char trailing_char = url ? '.' : '='; + unsigned char trailing_char = url ? '.' : '='; - // - // Choose set of base64 characters. They differ - // for the last two positions, depending on the url - // parameter. - // A bool (as is the parameter url) is guaranteed - // to evaluate to either 0 or 1 in C++ therefore, - // the correct character set is chosen by subscripting - // base64_chars with url. - // - const char* base64_chars_ = base64_chars[url]; + // + // Choose set of base64 characters. They differ + // for the last two positions, depending on the url + // parameter. + // A bool (as is the parameter url) is guaranteed + // to evaluate to either 0 or 1 in C++ therefore, + // the correct character set is chosen by subscripting + // base64_chars with url. + // + const char* base64_chars_ = base64_chars[url]; - std::string ret; - ret.reserve(len_encoded); + std::string ret; + ret.reserve(len_encoded); - unsigned int pos = 0; + unsigned int pos = 0; - while (pos < in_len) { - ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0xfc) >> 2]); + while (pos < in_len) { + ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0xfc) >> 2]); - if (pos+1 < in_len) { - ret.push_back(base64_chars_[((bytes_to_encode[pos + 0] & 0x03) << 4) + ((bytes_to_encode[pos + 1] & 0xf0) >> 4)]); + if (pos + 1 < in_len) { + ret.push_back(base64_chars_[((bytes_to_encode[pos + 0] & 0x03) << 4) + ((bytes_to_encode[pos + 1] & 0xf0) >> 4)]); - if (pos+2 < in_len) { - ret.push_back(base64_chars_[((bytes_to_encode[pos + 1] & 0x0f) << 2) + ((bytes_to_encode[pos + 2] & 0xc0) >> 6)]); - ret.push_back(base64_chars_[ bytes_to_encode[pos + 2] & 0x3f]); - } - else { - ret.push_back(base64_chars_[(bytes_to_encode[pos + 1] & 0x0f) << 2]); - ret.push_back(trailing_char); - } - } - else { - - ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0x03) << 4]); - ret.push_back(trailing_char); - ret.push_back(trailing_char); - } + if (pos + 2 < in_len) { + ret.push_back(base64_chars_[((bytes_to_encode[pos + 1] & 0x0f) << 2) + ((bytes_to_encode[pos + 2] & 0xc0) >> 6)]); + ret.push_back(base64_chars_[bytes_to_encode[pos + 2] & 0x3f]); + } + else { + ret.push_back(base64_chars_[(bytes_to_encode[pos + 1] & 0x0f) << 2]); + ret.push_back(trailing_char); + } + } + else { - pos += 3; + ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0x03) << 4]); + ret.push_back(trailing_char); + ret.push_back(trailing_char); } + pos += 3; + } + - return ret; + return ret; } template -static std::string decode(String const& encoded_string, bool remove_linebreaks) { - // - // decode(…) is templated so that it can be used with String = const std::string& - // or std::string_view (requires at least C++17) - // +static std::string decode(String const& encoded_string, bool remove_linebreaks) +{ + // + // decode(…) is templated so that it can be used with String = const std::string& + // or std::string_view (requires at least C++17) + // - if (encoded_string.empty()) return std::string(); + if (encoded_string.empty()) return std::string(); - if (remove_linebreaks) { + if (remove_linebreaks) { - std::string copy(encoded_string); + std::string copy(encoded_string); - copy.erase(std::remove(copy.begin(), copy.end(), '\n'), copy.end()); + copy.erase(std::remove(copy.begin(), copy.end(), '\n'), copy.end()); - return base64_decode(copy, false); - } + return base64_decode(copy, false); + } - size_t length_of_string = encoded_string.length(); - size_t pos = 0; + size_t length_of_string = encoded_string.length(); + size_t pos = 0; - // - // The approximate length (bytes) of the decoded string might be one or - // two bytes smaller, depending on the amount of trailing equal signs - // in the encoded string. This approximation is needed to reserve - // enough space in the string to be returned. - // - size_t approx_length_of_decoded_string = length_of_string / 4 * 3; - std::string ret; - ret.reserve(approx_length_of_decoded_string); + // + // The approximate length (bytes) of the decoded string might be one or + // two bytes smaller, depending on the amount of trailing equal signs + // in the encoded string. This approximation is needed to reserve + // enough space in the string to be returned. + // + size_t approx_length_of_decoded_string = length_of_string / 4 * 3; + std::string ret; + ret.reserve(approx_length_of_decoded_string); - while (pos < length_of_string) { + while (pos < length_of_string) { // // Iterate over encoded input string in chunks. The size of all // chunks except the last one is 4 bytes. @@ -204,56 +212,58 @@ static std::string decode(String const& encoded_string, bool remove_linebreaks) // The last chunk produces at least one and up to three bytes. // - size_t pos_of_char_1 = pos_of_char(encoded_string.at(pos+1) ); + size_t pos_of_char_1 = pos_of_char(encoded_string.at(pos + 1)); // // Emit the first output byte that is produced in each chunk: // - ret.push_back(static_cast( ( (pos_of_char(encoded_string.at(pos+0)) ) << 2 ) + ( (pos_of_char_1 & 0x30 ) >> 4))); - - if ( ( pos + 2 < length_of_string ) && // Check for data that is not padded with equal signs (which is allowed by RFC 2045) - encoded_string.at(pos+2) != '=' && - encoded_string.at(pos+2) != '.' // accept URL-safe base 64 strings, too, so check for '.' also. - ) - { - // - // Emit a chunk's second byte (which might not be produced in the last chunk). - // - unsigned int pos_of_char_2 = pos_of_char(encoded_string.at(pos+2) ); - ret.push_back(static_cast( (( pos_of_char_1 & 0x0f) << 4) + (( pos_of_char_2 & 0x3c) >> 2))); - - if ( ( pos + 3 < length_of_string ) && - encoded_string.at(pos+3) != '=' && - encoded_string.at(pos+3) != '.' - ) - { - // - // Emit a chunk's third byte (which might not be produced in the last chunk). - // - ret.push_back(static_cast( ( (pos_of_char_2 & 0x03 ) << 6 ) + pos_of_char(encoded_string.at(pos+3)) )); - } - } - - pos += 4; + ret.push_back(static_cast(((pos_of_char(encoded_string.at(pos + 0))) << 2) + ((pos_of_char_1 & 0x30) >> 4))); + + if ((pos + 2 < length_of_string) && // Check for data that is not padded with equal signs (which is allowed by RFC 2045) + encoded_string.at(pos + 2) != '=' && + encoded_string.at(pos + 2) != '.' // accept URL-safe base 64 strings, too, so check for '.' also. + ) { + // + // Emit a chunk's second byte (which might not be produced in the last chunk). + // + unsigned int pos_of_char_2 = pos_of_char(encoded_string.at(pos + 2)); + ret.push_back(static_cast(((pos_of_char_1 & 0x0f) << 4) + ((pos_of_char_2 & 0x3c) >> 2))); + + if ((pos + 3 < length_of_string) && + encoded_string.at(pos + 3) != '=' && + encoded_string.at(pos + 3) != '.' + ) { + // + // Emit a chunk's third byte (which might not be produced in the last chunk). + // + ret.push_back(static_cast(((pos_of_char_2 & 0x03) << 6) + pos_of_char(encoded_string.at(pos + 3)))); + } } - return ret; + pos += 4; + } + + return ret; } -std::string base64_decode(std::string const& s, bool remove_linebreaks) { - return decode(s, remove_linebreaks); +std::string base64_decode(std::string const& s, bool remove_linebreaks) +{ + return decode(s, remove_linebreaks); } -std::string base64_encode(std::string const& s, bool url) { - return encode(s, url); +std::string base64_encode(std::string const& s, bool url) +{ + return encode(s, url); } -std::string base64_encode_pem (std::string const& s) { - return encode_pem(s); +std::string base64_encode_pem(std::string const& s) +{ + return encode_pem(s); } -std::string base64_encode_mime(std::string const& s) { - return encode_mime(s); +std::string base64_encode_mime(std::string const& s) +{ + return encode_mime(s); } #if __cplusplus >= 201703L @@ -263,20 +273,24 @@ std::string base64_encode_mime(std::string const& s) { // Provided by Yannic Bonenberger (https://github.com/Yannic) // -std::string base64_encode(std::string_view s, bool url) { - return encode(s, url); +std::string base64_encode(std::string_view s, bool url) +{ + return encode(s, url); } -std::string base64_encode_pem(std::string_view s) { - return encode_pem(s); +std::string base64_encode_pem(std::string_view s) +{ + return encode_pem(s); } -std::string base64_encode_mime(std::string_view s) { - return encode_mime(s); +std::string base64_encode_mime(std::string_view s) +{ + return encode_mime(s); } -std::string base64_decode(std::string_view s, bool remove_linebreaks) { - return decode(s, remove_linebreaks); +std::string base64_decode(std::string_view s, bool remove_linebreaks) +{ + return decode(s, remove_linebreaks); } #endif // __cplusplus >= 201703L diff --git a/flutter_inappwebview_windows/windows/utils/base64.h b/flutter_inappwebview_windows/windows/utils/base64.h index 4860d63d8..5e74e2f70 100644 --- a/flutter_inappwebview_windows/windows/utils/base64.h +++ b/flutter_inappwebview_windows/windows/utils/base64.h @@ -12,8 +12,8 @@ #include #endif // __cplusplus >= 201703L -std::string base64_encode (std::string const& s, bool url = false); -std::string base64_encode_pem (std::string const& s); +std::string base64_encode(std::string const& s, bool url = false); +std::string base64_encode_pem(std::string const& s); std::string base64_encode_mime(std::string const& s); std::string base64_decode(std::string const& s, bool remove_linebreaks = false); @@ -25,8 +25,8 @@ std::string base64_encode(unsigned char const*, size_t len, bool url = false); // Requires C++17 // Provided by Yannic Bonenberger (https://github.com/Yannic) // -std::string base64_encode (std::string_view s, bool url = false); -std::string base64_encode_pem (std::string_view s); +std::string base64_encode(std::string_view s, bool url = false); +std::string base64_encode_pem(std::string_view s); std::string base64_encode_mime(std::string_view s); std::string base64_decode(std::string_view s, bool remove_linebreaks = false); diff --git a/flutter_inappwebview_windows/windows/utils/defer.h b/flutter_inappwebview_windows/windows/utils/defer.h new file mode 100644 index 000000000..80a6b6ba2 --- /dev/null +++ b/flutter_inappwebview_windows/windows/utils/defer.h @@ -0,0 +1,15 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_DEFER_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_DEFER_H_ + +#include +#include + +namespace flutter_inappwebview_plugin +{ + static inline std::shared_ptr defer(void* handle, const std::function& callback) + { + return std::shared_ptr(handle, callback); + } +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_DEFER_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/utils/flutter.h b/flutter_inappwebview_windows/windows/utils/flutter.h index 45c1390cf..b3f03339e 100644 --- a/flutter_inappwebview_windows/windows/utils/flutter.h +++ b/flutter_inappwebview_windows/windows/utils/flutter.h @@ -122,8 +122,8 @@ namespace flutter_inappwebview_plugin template::value, bool>::type* = nullptr> static inline std::optional get_optional_fl_map_value(const flutter::EncodableMap& map, const char* key) { - if (fl_map_contains_not_null(map, key)) { - auto fl_key = make_fl_value(key); + auto fl_key = make_fl_value(key); + if (fl_map_contains_not_null(map, key) && (std::holds_alternative(map.at(fl_key)) || std::holds_alternative(map.at(fl_key)))) { return std::make_optional(map.at(fl_key).LongValue()); } return std::nullopt; @@ -132,8 +132,8 @@ namespace flutter_inappwebview_plugin template::value, bool>::type* = nullptr> static inline std::optional get_optional_fl_map_value(const flutter::EncodableMap& map, const char* key) { - if (fl_map_contains_not_null(map, key)) { - auto fl_key = make_fl_value(key); + auto fl_key = make_fl_value(key); + if (fl_map_contains_not_null(map, key) && (std::holds_alternative(map.at(fl_key)) || std::holds_alternative(map.at(fl_key)))) { return std::make_optional(map.at(fl_key).LongValue()); } return std::nullopt; @@ -177,7 +177,7 @@ namespace flutter_inappwebview_plugin auto flList = std::get_if(&map.at(make_fl_value(key))); if (flList) { - T vecValue(flList->size()); + T vecValue; for (auto itr = flList->begin(); itr != flList->end(); itr++) { vecValue.push_back(std::get(*itr)); } diff --git a/flutter_inappwebview_windows/windows/utils/string.h b/flutter_inappwebview_windows/windows/utils/string.h index 618e18f1c..50e18db24 100644 --- a/flutter_inappwebview_windows/windows/utils/string.h +++ b/flutter_inappwebview_windows/windows/utils/string.h @@ -188,6 +188,14 @@ namespace flutter_inappwebview_plugin { return str.size() >= suffix.size() && str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; } + + constexpr uint32_t string_hash(const std::string_view data) noexcept + { + uint32_t hash = 5381; + for (const auto& e : data) + hash = ((hash << 5) + hash) + e; + return hash; + }; } #endif //FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_STRING_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/utils/timer.h b/flutter_inappwebview_windows/windows/utils/timer.h new file mode 100644 index 000000000..198293384 --- /dev/null +++ b/flutter_inappwebview_windows/windows/utils/timer.h @@ -0,0 +1,70 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_TIMER_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_TIMER_H_ + +#include +#include +#include + +#include "map.h" + +namespace flutter_inappwebview_plugin +{ + class Timer { + public: + static UINT_PTR setTimeout(std::function callback, uint32_t delay) + { + auto timerId = SetTimer(NULL, 0, delay, (TIMERPROC)&Timer::timerCallback_); + // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-settimer#return-value + if (timerId != 0) { + timeoutCallbacks_[timerId] = callback; + } + return timerId; + } + + static UINT_PTR setInterval(std::function callback, uint32_t delay) + { + auto timerId = SetTimer(NULL, 0, delay, (TIMERPROC)&Timer::timerCallback_); + // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-settimer#return-value + if (timerId != 0) { + intervalCallbacks_[timerId] = callback; + } + return timerId; + } + + static bool clearTimeout(UINT_PTR timerId) + { + if (map_contains(timeoutCallbacks_, timerId)) { + timeoutCallbacks_.erase(timerId); + return (bool)KillTimer(NULL, timerId); + } + return false; + } + + static bool clearInterval(UINT_PTR timerId) + { + if (map_contains(intervalCallbacks_, timerId)) { + intervalCallbacks_.erase(timerId); + return (bool)KillTimer(NULL, timerId); + } + return false; + } + private: + static inline std::map> timeoutCallbacks_ = {}; + static inline std::map> intervalCallbacks_ = {}; + static void CALLBACK timerCallback_(HWND hwnd, UINT uMsg, UINT_PTR timerId, DWORD dwTime) + { + if (map_contains(timeoutCallbacks_, timerId)) { + timeoutCallbacks_.at(timerId)(); + clearTimeout(timerId); + } + else if (map_contains(intervalCallbacks_, timerId)) { + intervalCallbacks_.at(timerId)(); + } + else { + KillTimer(NULL, timerId); + } + } + }; +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_TIMER_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/utils/uri.h b/flutter_inappwebview_windows/windows/utils/uri.h new file mode 100644 index 000000000..6705a358a --- /dev/null +++ b/flutter_inappwebview_windows/windows/utils/uri.h @@ -0,0 +1,39 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_URI_UTIL_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_URI_UTIL_H_ + +#include +#include + +#include "string.h" + +namespace flutter_inappwebview_plugin { + static inline std::string get_origin_from_url(const std::string &url) { + try { + winrt::Windows::Foundation::Uri const uri{utf8_to_wide(url)}; + auto scheme = winrt::to_string(uri.SchemeName()); + auto host = winrt::to_string(uri.Host()); + if (!scheme.empty() && !host.empty()) { + auto uriPort = uri.Port(); + std::string port = ""; + if (uriPort > 0 && ((string_equals(scheme, "http") && uriPort != 80) || + (string_equals(scheme, "https") && uriPort != 443))) { + port = ":" + std::to_string(uriPort); + } + return scheme + "://" + host + port; + } + } + catch (...) {} + auto urlSplit = split(url, std::string{"://"}); + if (urlSplit.size() > 1) { + auto scheme = urlSplit[0]; + auto afterScheme = urlSplit[1]; + auto afterSchemeSplit = split(afterScheme, std::string{"/"}); + auto host = afterSchemeSplit[0]; + return scheme + "://" + host; + } + + return url; + } +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_URI_UTIL_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/utils/util.h b/flutter_inappwebview_windows/windows/utils/util.h index bbac292d2..99e6d9960 100644 --- a/flutter_inappwebview_windows/windows/utils/util.h +++ b/flutter_inappwebview_windows/windows/utils/util.h @@ -2,9 +2,9 @@ #define FLUTTER_INAPPWEBVIEW_PLUGIN_UTIL_H_ #include +#include #include #include -#include namespace flutter_inappwebview_plugin { diff --git a/flutter_inappwebview_windows/windows/utils/uuid.h b/flutter_inappwebview_windows/windows/utils/uuid.h new file mode 100644 index 000000000..cf7396621 --- /dev/null +++ b/flutter_inappwebview_windows/windows/utils/uuid.h @@ -0,0 +1,25 @@ +#ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_UUID_UTIL_H_ +#define FLUTTER_INAPPWEBVIEW_PLUGIN_UUID_UTIL_H_ + +#include +#include + +namespace flutter_inappwebview_plugin { + static inline std::string get_uuid() + { + UUID uuid = { 0 }; + std::string guid; + + ::UuidCreate(&uuid); + + RPC_CSTR szUuid = NULL; + if (::UuidToStringA(&uuid, &szUuid) == RPC_S_OK) { + guid = (char*)szUuid; + ::RpcStringFreeA(&szUuid); + } + + return guid; + } +} + +#endif //FLUTTER_INAPPWEBVIEW_PLUGIN_UUID_UTIL_H_ \ No newline at end of file diff --git a/flutter_inappwebview_windows/windows/webview_environment/webview_environment.cpp b/flutter_inappwebview_windows/windows/webview_environment/webview_environment.cpp index 580a1787f..e8c5669b8 100644 --- a/flutter_inappwebview_windows/windows/webview_environment/webview_environment.cpp +++ b/flutter_inappwebview_windows/windows/webview_environment/webview_environment.cpp @@ -46,6 +46,14 @@ namespace flutter_inappwebview_plugin if (settings->targetCompatibleBrowserVersion.has_value()) { options->put_TargetCompatibleBrowserVersion(utf8_to_wide(settings->targetCompatibleBrowserVersion.value()).c_str()); } + wil::com_ptr options2; + if (succeededOrLog(options->QueryInterface(IID_PPV_ARGS(&options2))) && settings->exclusiveUserDataFolderAccess.has_value()) { + options2->put_ExclusiveUserDataFolderAccess(settings->exclusiveUserDataFolderAccess.value()); + } + wil::com_ptr options3; + if (succeededOrLog(options->QueryInterface(IID_PPV_ARGS(&options3))) && settings->isCustomCrashReportingEnabled.has_value()) { + options3->put_IsCustomCrashReportingEnabled(settings->isCustomCrashReportingEnabled.value()); + } wil::com_ptr options4; if (succeededOrLog(options->QueryInterface(IID_PPV_ARGS(&options4))) && settings->customSchemeRegistrations.has_value()) { std::vector registrations = {}; @@ -54,6 +62,27 @@ namespace flutter_inappwebview_plugin } options4->SetCustomSchemeRegistrations(static_cast(registrations.size()), registrations.data()); } + wil::com_ptr options5; + if (succeededOrLog(options->QueryInterface(IID_PPV_ARGS(&options5))) && settings->enableTrackingPrevention.has_value()) { + options5->put_EnableTrackingPrevention(settings->enableTrackingPrevention.value()); + } + wil::com_ptr options6; + if (succeededOrLog(options->QueryInterface(IID_PPV_ARGS(&options6))) && settings->areBrowserExtensionsEnabled.has_value()) { + options6->put_AreBrowserExtensionsEnabled(settings->areBrowserExtensionsEnabled.value()); + } + wil::com_ptr options7; + if (succeededOrLog(options->QueryInterface(IID_PPV_ARGS(&options7)))) { + if (settings->channelSearchKind.has_value()) { + options7->put_ChannelSearchKind(static_cast(settings->channelSearchKind.value())); + } + if (settings->releaseChannels.has_value()) { + options7->put_ReleaseChannels(static_cast(settings->releaseChannels.value())); + } + } + wil::com_ptr options8; + if (succeededOrLog(options->QueryInterface(IID_PPV_ARGS(&options8))) && settings->scrollbarStyle.has_value()) { + options8->put_ScrollBarStyle(static_cast(settings->scrollbarStyle.value())); + } } auto hr = CreateCoreWebView2EnvironmentWithOptions( @@ -66,23 +95,71 @@ namespace flutter_inappwebview_plugin if (succeededOrLog(result)) { environment_ = std::move(environment); - auto hr = environment_->CreateCoreWebView2Controller(hwnd, Callback( - [this, completionHandler](HRESULT result, wil::com_ptr controller) -> HRESULT + auto add_NewBrowserVersionAvailable_HResult = environment_->add_NewBrowserVersionAvailable(Callback( + [this](ICoreWebView2Environment* sender, IUnknown* args) { - if (succeededOrLog(result)) { - webViewController_ = std::move(controller); - webViewController_->get_CoreWebView2(&webView_); - webViewController_->put_IsVisible(false); - } - if (completionHandler) { - completionHandler(result); + if (channelDelegate) { + channelDelegate->onNewBrowserVersionAvailable(); } return S_OK; - }).Get()); + } + ).Get(), &newBrowserVersionAvailableToken_); + failedLog(add_NewBrowserVersionAvailable_HResult); + + if (auto environment5 = environment_.try_query()) { + auto add_BrowserProcessExited_HResult = environment5->add_BrowserProcessExited(Callback( + [this](ICoreWebView2Environment* sender, ICoreWebView2BrowserProcessExitedEventArgs* args) + { + if (channelDelegate) { + COREWEBVIEW2_BROWSER_PROCESS_EXIT_KIND exitKind; + std::optional kind = SUCCEEDED(args->get_BrowserProcessExitKind(&exitKind)) ? static_cast(exitKind) : std::optional{}; - if (failedAndLog(hr) && completionHandler) { - completionHandler(hr); + UINT32 pid; + std::optional processId = SUCCEEDED(args->get_BrowserProcessId(&pid)) ? static_cast(pid) : std::optional{}; + + auto browserProcessExitedDetail = std::make_shared(kind, processId); + channelDelegate->onBrowserProcessExited(std::move(browserProcessExitedDetail)); + } + return S_OK; + } + ).Get(), &browserProcessExitedToken_); + failedLog(add_BrowserProcessExited_HResult); } + + if (auto environment8 = environment_.try_query()) { + auto add_ProcessInfosChanged_HResult = environment8->add_ProcessInfosChanged(Callback( + [this, environment8](ICoreWebView2Environment* sender, IUnknown* args) + { + if (!environment_) { + return S_OK; + } + if (auto environment13 = environment_.try_query()) { + auto hr = environment13->GetProcessExtendedInfos(Callback( + [this](HRESULT error, wil::com_ptr processCollection) -> HRESULT + { + if (succeededOrLog(error) && processCollection) { + auto browserProcessInfosChangedDetail = BrowserProcessInfosChangedDetail::fromICoreWebView2ProcessExtendedInfoCollection(processCollection); + channelDelegate->onProcessInfosChanged(std::move(browserProcessInfosChangedDetail)); + } + return S_OK; + }).Get()); + + if (succeededOrLog(hr)) { + return S_OK; + } + } + wil::com_ptr processCollection; + if (channelDelegate && succeededOrLog(environment8->GetProcessInfos(&processCollection))) { + auto browserProcessInfosChangedDetail = BrowserProcessInfosChangedDetail::fromICoreWebView2ProcessInfoCollection(processCollection); + channelDelegate->onProcessInfosChanged(std::move(browserProcessInfosChangedDetail)); + } + return S_OK; + } + ).Get(), &processInfosChangedToken_); + failedLog(add_ProcessInfosChanged_HResult); + } + + completionHandler(S_OK); } else if (completionHandler) { completionHandler(result); @@ -95,8 +172,154 @@ namespace flutter_inappwebview_plugin } } + void WebViewEnvironment::useTempWebView(const std::function, wil::com_ptr)> completionHandler) const + { + auto hwnd = plugin->webViewEnvironmentManager->getHWND(); + if (!hwnd) { + if (completionHandler) { + completionHandler(nullptr, nullptr); + } + return; + } + + auto hr = environment_->CreateCoreWebView2Controller(hwnd, Callback( + [this, completionHandler](HRESULT result, wil::com_ptr controller) -> HRESULT + { + if (succeededOrLog(result)) { + controller->put_IsVisible(false); + + wil::com_ptr webView_; + controller->get_CoreWebView2(&webView_); + + if (completionHandler) { + completionHandler(std::move(controller), std::move(webView_)); + } + } + else if (completionHandler) { + completionHandler(nullptr, nullptr); + } + return S_OK; + }).Get()); + + if (failedAndLog(hr) && completionHandler) { + completionHandler(nullptr, nullptr); + } + } + + bool WebViewEnvironment::isInterfaceSupported(const std::string& interfaceName) const + { + if (!environment_) { + return false; + } + + if (starts_with(interfaceName, std::string{ "ICoreWebView2Environment" })) { + switch (string_hash(interfaceName)) { + case string_hash("ICoreWebView2Environment"): + return environment_.try_query() != nullptr; + case string_hash("ICoreWebView2Environment2"): + return environment_.try_query() != nullptr; + case string_hash("ICoreWebView2Environment3"): + return environment_.try_query() != nullptr; + case string_hash("ICoreWebView2Environment4"): + return environment_.try_query() != nullptr; + case string_hash("ICoreWebView2Environment5"): + return environment_.try_query() != nullptr; + case string_hash("ICoreWebView2Environment6"): + return environment_.try_query() != nullptr; + case string_hash("ICoreWebView2Environment7"): + return environment_.try_query() != nullptr; + case string_hash("ICoreWebView2Environment8"): + return environment_.try_query() != nullptr; + case string_hash("ICoreWebView2Environment9"): + return environment_.try_query() != nullptr; + case string_hash("ICoreWebView2Environment10"): + return environment_.try_query() != nullptr; + case string_hash("ICoreWebView2Environment11"): + return environment_.try_query() != nullptr; + case string_hash("ICoreWebView2Environment12"): + return environment_.try_query() != nullptr; + case string_hash("ICoreWebView2Environment13"): + return environment_.try_query() != nullptr; + case string_hash("ICoreWebView2Environment14"): + return environment_.try_query() != nullptr; + default: + return false; + } + } + + return false; + } + + void WebViewEnvironment::getProcessInfos(const std::function>)> completionHandler) const + { + if (!environment_) { + if (completionHandler) { + completionHandler({}); + } + return; + } + + if (auto environment13 = environment_.try_query()) { + auto hr = environment13->GetProcessExtendedInfos(Callback( + [completionHandler](HRESULT error, wil::com_ptr processCollection) -> HRESULT + { + std::vector> processInfos = {}; + if (succeededOrLog(error) && processCollection) { + auto browserProcessInfosChangedDetail = BrowserProcessInfosChangedDetail::fromICoreWebView2ProcessExtendedInfoCollection(processCollection); + processInfos = browserProcessInfosChangedDetail->infos; + } + if (completionHandler) { + completionHandler(processInfos); + } + return S_OK; + }).Get()); + + if (succeededOrLog(hr)) { + return; + } + } + std::vector> processInfos = {}; + if (auto environment8 = environment_.try_query()) { + wil::com_ptr processCollection; + if (succeededOrLog(environment8->GetProcessInfos(&processCollection))) { + auto browserProcessInfosChangedDetail = BrowserProcessInfosChangedDetail::fromICoreWebView2ProcessInfoCollection(processCollection); + processInfos = browserProcessInfosChangedDetail->infos; + } + } + + if (completionHandler) { + completionHandler(processInfos); + } + } + + std::optional WebViewEnvironment::getFailureReportFolderPath() const + { + if (!environment_) { + return std::optional{}; + } + + if (auto environment11 = environment_.try_query()) { + wil::unique_cotaskmem_string failureReportFolderPath; + if (succeededOrLog(environment11->get_FailureReportFolderPath(&failureReportFolderPath))) { + return wide_to_utf8(failureReportFolderPath.get()); + } + } + + return std::optional{}; + } + WebViewEnvironment::~WebViewEnvironment() { debugLog("dealloc WebViewEnvironment"); + if (environment_) { + environment_->remove_NewBrowserVersionAvailable(newBrowserVersionAvailableToken_); + if (auto environment5 = environment_.try_query()) { + environment5->remove_BrowserProcessExited(browserProcessExitedToken_); + } + if (auto environment8 = environment_.try_query()) { + environment8->remove_ProcessInfosChanged(processInfosChangedToken_); + } + } + environment_ = nullptr; } } diff --git a/flutter_inappwebview_windows/windows/webview_environment/webview_environment.h b/flutter_inappwebview_windows/windows/webview_environment/webview_environment.h index 615442d4b..7ac937993 100644 --- a/flutter_inappwebview_windows/windows/webview_environment/webview_environment.h +++ b/flutter_inappwebview_windows/windows/webview_environment/webview_environment.h @@ -2,6 +2,8 @@ #define FLUTTER_INAPPWEBVIEW_PLUGIN_WEBVIEW_ENVIRONMENT_H_ #include +#include +#include #include #include @@ -30,18 +32,17 @@ namespace flutter_inappwebview_plugin { return environment_; } - wil::com_ptr getWebViewController() - { - return webViewController_; - } - wil::com_ptr getWebView() - { - return webView_; - } + // without using a "temp" ICoreWebView2 for CookieManager and other possible usage, the onBrowserProcessExited event will never be called + void useTempWebView(const std::function, wil::com_ptr)> completionHandler) const; + bool isInterfaceSupported(const std::string& interfaceName) const; + void getProcessInfos(const std::function>)> completionHandler) const; + std::optional getFailureReportFolderPath() const; + private: wil::com_ptr environment_; - wil::com_ptr webViewController_; - wil::com_ptr webView_; + EventRegistrationToken processInfosChangedToken_ = { 0 }; + EventRegistrationToken browserProcessExitedToken_ = { 0 }; + EventRegistrationToken newBrowserVersionAvailableToken_ = { 0 }; WNDCLASS windowClass_ = {}; }; } diff --git a/flutter_inappwebview_windows/windows/webview_environment/webview_environment_channel_delegate.cpp b/flutter_inappwebview_windows/windows/webview_environment/webview_environment_channel_delegate.cpp index d5b9e4d22..d8546427d 100644 --- a/flutter_inappwebview_windows/windows/webview_environment/webview_environment_channel_delegate.cpp +++ b/flutter_inappwebview_windows/windows/webview_environment/webview_environment_channel_delegate.cpp @@ -2,6 +2,7 @@ #include "../utils/log.h" #include "../utils/strconv.h" #include "../utils/string.h" +#include "../utils/vector.h" #include "webview_environment.h" #include "webview_environment_channel_delegate.h" @@ -21,7 +22,7 @@ namespace flutter_inappwebview_plugin return; } - // auto& arguments = std::get(*method_call.arguments()); + auto& arguments = std::get(*method_call.arguments()); auto& methodName = method_call.method_name(); if (string_equals(methodName, "dispose")) { @@ -34,11 +35,53 @@ namespace flutter_inappwebview_plugin } result->Success(); } + else if (string_equals(methodName, "isInterfaceSupported")) { + auto interfaceName = get_fl_map_value(arguments, "interface"); + result->Success(webViewEnvironment->isInterfaceSupported(interfaceName)); + } + else if (string_equals(methodName, "getProcessInfos")) { + auto result_ = std::shared_ptr>(std::move(result)); + webViewEnvironment->getProcessInfos([result_ = std::move(result_)](std::vector> processInfos) + { + result_->Success(make_fl_value(functional_map(processInfos, [](const std::shared_ptr& info) { return info->toEncodableMap(); }))); + }); + } + else if (string_equals(methodName, "getFailureReportFolderPath")) { + result->Success(make_fl_value(webViewEnvironment->getFailureReportFolderPath())); + } else { result->NotImplemented(); } } + void WebViewEnvironmentChannelDelegate::onNewBrowserVersionAvailable() const + { + if (!channel) { + return; + } + channel->InvokeMethod("onNewBrowserVersionAvailable", nullptr); + } + + void WebViewEnvironmentChannelDelegate::onBrowserProcessExited(std::shared_ptr detail) const + { + if (!channel) { + return; + } + + auto arguments = std::make_unique(detail->toEncodableMap()); + channel->InvokeMethod("onBrowserProcessExited", std::move(arguments)); + } + + void WebViewEnvironmentChannelDelegate::onProcessInfosChanged(std::shared_ptr detail) const + { + if (!channel) { + return; + } + + auto arguments = std::make_unique(detail->toEncodableMap()); + channel->InvokeMethod("onProcessInfosChanged", std::move(arguments)); + } + WebViewEnvironmentChannelDelegate::~WebViewEnvironmentChannelDelegate() { debugLog("dealloc WebViewEnvironmentChannelDelegate"); diff --git a/flutter_inappwebview_windows/windows/webview_environment/webview_environment_channel_delegate.h b/flutter_inappwebview_windows/windows/webview_environment/webview_environment_channel_delegate.h index b98e67abf..c51c18f05 100644 --- a/flutter_inappwebview_windows/windows/webview_environment/webview_environment_channel_delegate.h +++ b/flutter_inappwebview_windows/windows/webview_environment/webview_environment_channel_delegate.h @@ -1,9 +1,12 @@ #ifndef FLUTTER_INAPPWEBVIEW_PLUGIN_WEBVIEW_ENVIRONMENT_CHANNEL_DELEGATE_H_ #define FLUTTER_INAPPWEBVIEW_PLUGIN_WEBVIEW_ENVIRONMENT_CHANNEL_DELEGATE_H_ -#include "../types/channel_delegate.h" #include +#include "../types/browser_process_exited_detail.h" +#include "../types/browser_process_infos_changed_detail.h" +#include "../types/channel_delegate.h" + namespace flutter_inappwebview_plugin { class WebViewEnvironment; @@ -19,6 +22,10 @@ namespace flutter_inappwebview_plugin void HandleMethodCall( const flutter::MethodCall& method_call, std::unique_ptr> result); + + void onNewBrowserVersionAvailable() const; + void onBrowserProcessExited(std::shared_ptr detail) const; + void onProcessInfosChanged(std::shared_ptr detail) const; }; } diff --git a/flutter_inappwebview_windows/windows/webview_environment/webview_environment_settings.cpp b/flutter_inappwebview_windows/windows/webview_environment/webview_environment_settings.cpp index 7667f6003..95802937a 100644 --- a/flutter_inappwebview_windows/windows/webview_environment/webview_environment_settings.cpp +++ b/flutter_inappwebview_windows/windows/webview_environment/webview_environment_settings.cpp @@ -10,7 +10,14 @@ namespace flutter_inappwebview_plugin allowSingleSignOnUsingOSPrimaryAccount(get_optional_fl_map_value(map, "allowSingleSignOnUsingOSPrimaryAccount")), language(get_optional_fl_map_value(map, "language")), targetCompatibleBrowserVersion(get_optional_fl_map_value(map, "targetCompatibleBrowserVersion")), - customSchemeRegistrations(functional_map(get_optional_fl_map_value(map, "customSchemeRegistrations"), [](const flutter::EncodableValue& m) { return std::make_shared(std::get(m)); })) + customSchemeRegistrations(functional_map(get_optional_fl_map_value(map, "customSchemeRegistrations"), [](const flutter::EncodableValue& m) { return std::make_shared(std::get(m)); })), + exclusiveUserDataFolderAccess(get_optional_fl_map_value(map, "exclusiveUserDataFolderAccess")), + isCustomCrashReportingEnabled(get_optional_fl_map_value(map, "isCustomCrashReportingEnabled")), + enableTrackingPrevention(get_optional_fl_map_value(map, "enableTrackingPrevention")), + areBrowserExtensionsEnabled(get_optional_fl_map_value(map, "areBrowserExtensionsEnabled")), + channelSearchKind(get_optional_fl_map_value(map, "channelSearchKind")), + releaseChannels(get_optional_fl_map_value(map, "releaseChannels")), + scrollbarStyle(get_optional_fl_map_value(map, "scrollbarStyle")) {} flutter::EncodableMap WebViewEnvironmentSettings::toEncodableMap() const @@ -22,7 +29,14 @@ namespace flutter_inappwebview_plugin {"allowSingleSignOnUsingOSPrimaryAccount", make_fl_value(allowSingleSignOnUsingOSPrimaryAccount)}, {"language", make_fl_value(language)}, {"targetCompatibleBrowserVersion", make_fl_value(targetCompatibleBrowserVersion)}, - {"customSchemeRegistrations", make_fl_value(functional_map(customSchemeRegistrations, [](const std::shared_ptr& item) { return item->toEncodableMap(); }))} + {"customSchemeRegistrations", make_fl_value(functional_map(customSchemeRegistrations, [](const std::shared_ptr& item) { return item->toEncodableMap(); }))}, + {"exclusiveUserDataFolderAccess", make_fl_value(exclusiveUserDataFolderAccess)}, + {"isCustomCrashReportingEnabled", make_fl_value(isCustomCrashReportingEnabled)}, + {"enableTrackingPrevention", make_fl_value(enableTrackingPrevention)}, + {"areBrowserExtensionsEnabled", make_fl_value(areBrowserExtensionsEnabled)}, + {"channelSearchKind", make_fl_value(channelSearchKind)}, + {"releaseChannels", make_fl_value(releaseChannels)}, + {"scrollbarStyle", make_fl_value(scrollbarStyle)} }; } diff --git a/flutter_inappwebview_windows/windows/webview_environment/webview_environment_settings.h b/flutter_inappwebview_windows/windows/webview_environment/webview_environment_settings.h index 84314aac6..bef41b343 100644 --- a/flutter_inappwebview_windows/windows/webview_environment/webview_environment_settings.h +++ b/flutter_inappwebview_windows/windows/webview_environment/webview_environment_settings.h @@ -20,6 +20,13 @@ namespace flutter_inappwebview_plugin const std::optional language; const std::optional targetCompatibleBrowserVersion; const std::optional>> customSchemeRegistrations; + const std::optional exclusiveUserDataFolderAccess; + const std::optional isCustomCrashReportingEnabled; + const std::optional enableTrackingPrevention; + const std::optional areBrowserExtensionsEnabled; + const std::optional channelSearchKind; + const std::optional releaseChannels; + const std::optional scrollbarStyle; WebViewEnvironmentSettings() = default; WebViewEnvironmentSettings(const flutter::EncodableMap& map); diff --git a/package.json b/package.json index c41fa8b95..2487f6396 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "publish:dry": ".fvm/flutter_sdk/bin/flutter pub publish --dry-run", "format": ".fvm/flutter_sdk/bin/dart format flutter_inappwebview/lib flutter_inappwebview/example/integration_test flutter_inappwebview_platform_interface/lib flutter_inappwebview_android/lib flutter_inappwebview_ios/lib flutter_inappwebview_macos/lib flutter_inappwebview_web/lib flutter_inappwebview_windows/lib", - "docs:gen": "cd flutter_inappwebview && ../.fvm/flutter_sdk/bin/dart doc ../", + "docs:gen": "cd flutter_inappwebview && ../.fvm/flutter_sdk/bin/dart doc --output=../doc/api .", "docs:serve": ".fvm/flutter_sdk/bin/flutter pub global activate dhttpd && .fvm/flutter_sdk/bin/flutter pub global run dhttpd:dhttpd --path doc/api", "publish:platform_interface": "cd flutter_inappwebview_platform_interface && ../.fvm/flutter_sdk/bin/flutter pub publish && cd ..", diff --git a/test_node_server/index.js b/test_node_server/index.js index ad68fb3a7..72c0a8248 100755 --- a/test_node_server/index.js +++ b/test_node_server/index.js @@ -12,6 +12,7 @@ // - Overwrite certificate.pfx to example/test_assets/certificate.pfx const express = require('express'); const http = require('http'); +const net = require('net'); const https = require('https'); const cors = require('cors'); const auth = require('basic-auth'); @@ -224,19 +225,41 @@ app.get("/test-download-file", (req, res) => { app.listen(8082) // Proxy server -http.createServer(function (req, res) { - res.setHeader('Content-type', 'text/html'); - res.write(` - - - - -

Proxy Works

-

${req.url}

-

${req.method}

-

${JSON.stringify(req.headers)}

- - - `); - res.end(); -}).listen(8083); \ No newline at end of file +// Create an HTTP tunneling proxy +const proxy = http.createServer((req, res) => { + console.log('proxy response', req.url); + res.writeHead(200, { 'Content-Type': 'text/html' }); + res.end(` + + + + +

Proxy Works

+

${req.url}

+

${req.method}

+

${JSON.stringify(req.headers)}

+ + + `); +}); +proxy.on('connect', (req, clientSocket, head) => { + console.log('proxy connect request'); + // Connect to an origin server + // const { port, hostname } = new URL(`http://${req.url}`); + const { port, hostname } = new URL(`http://127.0.0.1:8083`); + const serverSocket = net.connect(port || 80, hostname, () => { + clientSocket.write('HTTP/1.1 200 Connection Established\r\n' + + 'Proxy-agent: Node.js-Proxy\r\n' + + '\r\n'); + serverSocket.write(head); + serverSocket.pipe(clientSocket); + clientSocket.pipe(serverSocket); + }); +}); +proxy.listen(8083, null, () => { + console.log('proxy server listening on port 8083'); +}); + +process.on('uncaughtException', function (err) { + console.error(err); +}); \ No newline at end of file diff --git a/web_support/.gitignore b/web_support/.gitignore new file mode 100644 index 000000000..32b877bcb --- /dev/null +++ b/web_support/.gitignore @@ -0,0 +1,11 @@ +/tmp +/out-tsc + +/node_modules +npm-debug.log* +yarn-debug.log* +yarn-error.log* +/.pnp +.pnp.js + +.vscode/* \ No newline at end of file diff --git a/web_support/package-lock.json b/web_support/package-lock.json new file mode 100644 index 000000000..8c549cccd --- /dev/null +++ b/web_support/package-lock.json @@ -0,0 +1,478 @@ +{ + "name": "web_support", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "web_support", + "version": "1.0.0", + "devDependencies": { + "esbuild": "^0.24.0", + "typescript": "^5.5.3" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz", + "integrity": "sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.0.tgz", + "integrity": "sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.0.tgz", + "integrity": "sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.0.tgz", + "integrity": "sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.0.tgz", + "integrity": "sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.0.tgz", + "integrity": "sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.0.tgz", + "integrity": "sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.0.tgz", + "integrity": "sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.0.tgz", + "integrity": "sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.0.tgz", + "integrity": "sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.0.tgz", + "integrity": "sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.0.tgz", + "integrity": "sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.0.tgz", + "integrity": "sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.0.tgz", + "integrity": "sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.0.tgz", + "integrity": "sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.0.tgz", + "integrity": "sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.0.tgz", + "integrity": "sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.0.tgz", + "integrity": "sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.0.tgz", + "integrity": "sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.0.tgz", + "integrity": "sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.0.tgz", + "integrity": "sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.0.tgz", + "integrity": "sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.0.tgz", + "integrity": "sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.0.tgz", + "integrity": "sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.0.tgz", + "integrity": "sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.24.0", + "@esbuild/android-arm": "0.24.0", + "@esbuild/android-arm64": "0.24.0", + "@esbuild/android-x64": "0.24.0", + "@esbuild/darwin-arm64": "0.24.0", + "@esbuild/darwin-x64": "0.24.0", + "@esbuild/freebsd-arm64": "0.24.0", + "@esbuild/freebsd-x64": "0.24.0", + "@esbuild/linux-arm": "0.24.0", + "@esbuild/linux-arm64": "0.24.0", + "@esbuild/linux-ia32": "0.24.0", + "@esbuild/linux-loong64": "0.24.0", + "@esbuild/linux-mips64el": "0.24.0", + "@esbuild/linux-ppc64": "0.24.0", + "@esbuild/linux-riscv64": "0.24.0", + "@esbuild/linux-s390x": "0.24.0", + "@esbuild/linux-x64": "0.24.0", + "@esbuild/netbsd-x64": "0.24.0", + "@esbuild/openbsd-arm64": "0.24.0", + "@esbuild/openbsd-x64": "0.24.0", + "@esbuild/sunos-x64": "0.24.0", + "@esbuild/win32-arm64": "0.24.0", + "@esbuild/win32-ia32": "0.24.0", + "@esbuild/win32-x64": "0.24.0" + } + }, + "node_modules/typescript": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + } + } +} diff --git a/web_support/package.json b/web_support/package.json new file mode 100644 index 000000000..8369d88e4 --- /dev/null +++ b/web_support/package.json @@ -0,0 +1,14 @@ +{ + "name": "web_support", + "version": "1.0.0", + "description": "", + "main": "", + "scripts": { + "build": "esbuild --format=esm --platform=browser --sourcemap=inline --bundle --outfile=../flutter_inappwebview_web/lib/assets/web/web_support.js src/index.ts" + }, + "devDependencies": { + "esbuild": "^0.24.0", + "typescript": "^5.5.3" + }, + "private": true +} diff --git a/web_support/src/index.ts b/web_support/src/index.ts new file mode 100644 index 000000000..38d5a67a0 --- /dev/null +++ b/web_support/src/index.ts @@ -0,0 +1,758 @@ +import { + InAppWebView, + InAppWebViewPlugin, + InAppWebViewSettings, + JavaScriptBridgeHandler, + UserScript, + UserScriptInjectionTime +} from "./types"; + +declare global { + interface Window { + flutter_inappwebview_plugin: InAppWebViewPlugin; + flutter_inappwebview?: JavaScriptBridgeHandler | null; + console: Console; + + eval(x: string): any; + } +} + +(function () { + let _JSON_stringify = window.JSON.stringify; + let _Array_slice = window.Array.prototype.slice; + _Array_slice.call = window.Function.prototype.call; + + window.flutter_inappwebview_plugin = { + createFlutterInAppWebView: function (viewId: number | string, iframe: HTMLIFrameElement, iframeContainer: HTMLDivElement, bridgeSecret: string) { + const iframeId = iframe.id; + const webView: InAppWebView = { + viewId: viewId, + iframeId: iframeId, + iframe: null, + iframeContainer: null, + isFullscreen: false, + documentTitle: null, + functionMap: {}, + settings: {}, + javaScriptBridgeEnabled: true, + disableContextMenuHandler: function (event: Event) { + event.preventDefault(); + event.stopPropagation(); + return false; + }, + prepare: function (settings: InAppWebViewSettings) { + webView.settings = settings; + + webView.javaScriptBridgeEnabled = webView.settings.javaScriptBridgeEnabled ?? true; + const javaScriptBridgeOriginAllowList = webView.settings.javaScriptBridgeOriginAllowList; + if (javaScriptBridgeOriginAllowList != null && !javaScriptBridgeOriginAllowList.includes("*")) { + if (javaScriptBridgeOriginAllowList.length === 0) { + // an empty list means that the JavaScript Bridge is not allowed for any origin. + webView.javaScriptBridgeEnabled = false; + } + } + + document.addEventListener('fullscreenchange', function (event: Event) { + // document.fullscreenElement will point to the element that + // is in fullscreen mode if there is one. If there isn't one, + // the value of the property is null. + if (document.fullscreenElement && document.fullscreenElement.id == iframeId) { + webView.isFullscreen = true; + _nativeCommunication('onEnterFullscreen', viewId); + } else if (!document.fullscreenElement && webView.isFullscreen) { + webView.isFullscreen = false; + _nativeCommunication('onExitFullscreen', viewId); + } else { + webView.isFullscreen = false; + } + }); + + if (iframe != null) { + webView.iframe = iframe; + webView.iframeContainer = iframeContainer; + iframe.addEventListener('load', function (event: Event) { + if (iframe.contentWindow == null) { + return; + } + + const userScriptsAtStart = _nativeCommunication('getUserOnlyScriptsAt', viewId, [UserScriptInjectionTime.AT_DOCUMENT_START]); + const userScriptsAtEnd = _nativeCommunication('getUserOnlyScriptsAt', viewId, [UserScriptInjectionTime.AT_DOCUMENT_END]); + + try { + let javaScriptBridgeEnabled = webView.javaScriptBridgeEnabled; + if (javaScriptBridgeOriginAllowList != null) { + javaScriptBridgeEnabled = javaScriptBridgeOriginAllowList + .map(allowedOriginRule => new RegExp(allowedOriginRule)) + .some((rx) => { + return rx.test(iframe.contentWindow!.location.origin); + }) + } + if (javaScriptBridgeEnabled) { + const javaScriptBridgeName = _nativeCommunication('getJavaScriptBridgeName', viewId); + // @ts-ignore + iframe.contentWindow![javaScriptBridgeName] = { + callHandler: function () { + let origin = ''; + let requestUrl = ''; + try { + origin = iframe.contentWindow!.location.origin; + } catch (_) { + } + try { + requestUrl = iframe.contentWindow!.location.href; + } catch (_) { + } + return _nativeCommunication('onCallJsHandler', + viewId, + [arguments[0], _JSON_stringify({ + 'origin': origin, + 'requestUrl': requestUrl, + 'isMainFrame': true, + '_bridgeSecret': bridgeSecret, + 'args': _JSON_stringify(_Array_slice.call(arguments, 1)) + })]); + } + } as JavaScriptBridgeHandler; + } + } catch (e) { + console.log(e); + } + + for (const userScript of [...userScriptsAtStart, ...userScriptsAtEnd]) { + let ifStatement = "if ("; + let source = userScript.source; + if (userScript.allowedOriginRules != null && !userScript.allowedOriginRules.includes("*")) { + if (userScript.allowedOriginRules.length === 0) { + // return empty source string if allowedOriginRules is an empty list. + // an empty list means that this UserScript is not allowed for any origin. + source = ""; + } + let jsRegExpArray = "["; + for (const allowedOriginRule of userScript.allowedOriginRules) { + if (jsRegExpArray.length > 1) { + jsRegExpArray += ","; + } + jsRegExpArray += `new RegExp('${allowedOriginRule.replace("\'", "\\'")}')`; + } + if (jsRegExpArray.length > 1) { + jsRegExpArray += "]"; + ifStatement += `${jsRegExpArray}.some(function(rx) { return rx.test(window.location.origin); })`; + } + } + webView.evaluateJavascript(ifStatement.length > 4 ? `${ifStatement}) { ${source} }` : source); + } + + let url = iframe.src; + try { + url = iframe.contentWindow.location.href; + } catch (e) { + console.log(e); + } + _nativeCommunication('onLoadStart', viewId, [url]); + + try { + const oldLogs = { + 'log': iframe.contentWindow.console.log, + 'debug': iframe.contentWindow.console.debug, + 'error': iframe.contentWindow.console.error, + 'info': iframe.contentWindow.console.info, + 'warn': iframe.contentWindow.console.warn + }; + for (const k in oldLogs) { + (function (oldLog) { + // @ts-ignore + iframe.contentWindow.console[oldLog] = function () { + var message = ''; + for (var i in arguments) { + if (message == '') { + message += arguments[i]; + } else { + message += ' ' + arguments[i]; + } + } + // @ts-ignore + oldLogs[oldLog].call(iframe.contentWindow.console, ...arguments); + _nativeCommunication('onConsoleMessage', viewId, [oldLog, message]); + } + })(k); + } + } catch (e) { + console.log(e); + } + + try { + const originalPushState = iframe.contentWindow.history.pushState; + iframe.contentWindow.history.pushState = function (state, unused, url) { + originalPushState.call(iframe.contentWindow!.history, state, unused, url); + let iframeUrl = iframe.src; + try { + iframeUrl = iframe.contentWindow!.location.href; + } catch (e) { + console.log(e); + } + _nativeCommunication('onUpdateVisitedHistory', viewId, [iframeUrl]); + }; + + const originalReplaceState = iframe.contentWindow.history.replaceState; + iframe.contentWindow.history.replaceState = function (state, unused, url) { + originalReplaceState.call(iframe.contentWindow!.history, state, unused, url); + let iframeUrl = iframe.src; + try { + iframeUrl = iframe.contentWindow!.location.href; + } catch (e) { + console.log(e); + } + _nativeCommunication('onUpdateVisitedHistory', viewId, [iframeUrl]); + }; + + const originalClose = iframe.contentWindow.close; + iframe.contentWindow.close = function () { + originalClose.call(iframe.contentWindow); + _nativeCommunication('onCloseWindow', viewId); + }; + + const originalOpen = iframe.contentWindow.open; + iframe.contentWindow.open = function (url, target, windowFeatures) { + const newWindow = originalOpen.call(iframe.contentWindow, ...arguments); + _nativeCommunication>('onCreateWindow', viewId, [url, target, windowFeatures]).then(function (handledByClient) { + if (handledByClient) { + newWindow?.close(); + } + }); + return newWindow; + }; + + const originalPrint = iframe.contentWindow.print; + iframe.contentWindow.print = function () { + let iframeUrl = iframe.src; + try { + iframeUrl = iframe.contentWindow!.location.href; + } catch (e) { + console.log(e); + } + _nativeCommunication('onPrintRequest', viewId, [iframeUrl]); + originalPrint.call(iframe.contentWindow); + }; + + webView.functionMap = { + "window.open": iframe.contentWindow.open, + } + + const initialTitle = iframe.contentDocument?.title; + const titleEl = iframe.contentDocument?.querySelector('title'); + webView.documentTitle = initialTitle; + _nativeCommunication('onTitleChanged', viewId, [initialTitle]); + if (titleEl != null) { + new MutationObserver(function (mutations) { + const title = (mutations[0].target as HTMLElement).innerText; + if (title != webView.documentTitle) { + webView.documentTitle = title; + _nativeCommunication('onTitleChanged', viewId, [title]); + } + }).observe( + titleEl, + {subtree: true, characterData: true, childList: true} + ); + } + + let oldPixelRatio = iframe.contentWindow.devicePixelRatio; + iframe.contentWindow.addEventListener('resize', function (e) { + const newPixelRatio = iframe.contentWindow!.devicePixelRatio; + if (newPixelRatio !== oldPixelRatio) { + _nativeCommunication('onZoomScaleChanged', viewId, [oldPixelRatio, newPixelRatio]); + oldPixelRatio = newPixelRatio; + } + }); + + iframe.contentWindow.addEventListener('popstate', function (event: Event) { + let iframeUrl = iframe.src; + try { + iframeUrl = iframe.contentWindow!.location.href; + } catch (e) { + console.log(e); + } + _nativeCommunication('onUpdateVisitedHistory', viewId, [iframeUrl]); + }); + + iframe.contentWindow.addEventListener('scroll', function (event: Event) { + let x = 0; + let y = 0; + try { + x = iframe.contentWindow!.scrollX; + y = iframe.contentWindow!.scrollY; + } catch (e) { + console.log(e); + } + _nativeCommunication('onScrollChanged', viewId, [x, y]); + }); + + iframe.contentWindow.addEventListener('focus', function (event: Event) { + _nativeCommunication('onWindowFocus', viewId); + }); + + iframe.contentWindow.addEventListener('blur', function (event: Event) { + _nativeCommunication('onWindowBlur', viewId); + }); + } catch (e) { + console.log(e); + } + + try { + if (!webView.settings.javaScriptCanOpenWindowsAutomatically) { + iframe.contentWindow.open = function () { + throw new Error('JavaScript cannot open windows automatically'); + }; + } + + if (!webView.settings.verticalScrollBarEnabled && !webView.settings.horizontalScrollBarEnabled) { + const style = iframe.contentDocument?.createElement('style'); + if (style != null) { + style.id = "settings.verticalScrollBarEnabled-settings.horizontalScrollBarEnabled"; + style.innerHTML = "body::-webkit-scrollbar { width: 0px; height: 0px; }"; + iframe.contentDocument?.head.append(style); + } + } + + if (webView.settings.disableVerticalScroll) { + const style = iframe.contentDocument?.createElement('style'); + if (style != null) { + style.id = "settings.disableVerticalScroll"; + style.innerHTML = "body { overflow-y: hidden; }"; + iframe.contentDocument?.head.append(style); + } + } + + if (webView.settings.disableHorizontalScroll) { + const style = iframe.contentDocument?.createElement('style'); + if (style != null) { + style.id = "settings.disableHorizontalScroll"; + style.innerHTML = "body { overflow-x: hidden; }"; + iframe.contentDocument?.head.append(style); + } + } + + if (webView.settings.disableContextMenu) { + iframe.contentWindow.addEventListener('contextmenu', webView.disableContextMenuHandler); + } + } catch (e) { + console.log(e); + } + + _nativeCommunication('onLoadStop', viewId, [url]); + + try { + iframe.contentWindow.dispatchEvent(new Event('flutterInAppWebViewPlatformReady')); + } catch (e) { + console.log(e); + } + + }); + } + }, + setSettings: function (newSettings: InAppWebViewSettings) { + const iframe = webView.iframe; + if (iframe == null) { + return; + } + try { + if (webView.settings.javaScriptCanOpenWindowsAutomatically != newSettings.javaScriptCanOpenWindowsAutomatically) { + if (!newSettings.javaScriptCanOpenWindowsAutomatically) { + iframe.contentWindow!.open = function () { + throw new Error('JavaScript cannot open windows automatically'); + }; + } else { + iframe.contentWindow!.open = webView.functionMap["window.open"]; + } + } + + if (webView.settings.verticalScrollBarEnabled != newSettings.verticalScrollBarEnabled && + webView.settings.horizontalScrollBarEnabled != newSettings.horizontalScrollBarEnabled) { + if (!newSettings.verticalScrollBarEnabled && !newSettings.horizontalScrollBarEnabled) { + const style = iframe.contentDocument?.createElement('style'); + if (style != null) { + style.id = "settings.verticalScrollBarEnabled-settings.horizontalScrollBarEnabled"; + style.innerHTML = "body::-webkit-scrollbar { width: 0px; height: 0px; }"; + iframe.contentDocument?.head.append(style); + } + } else { + const styleElement = iframe.contentDocument?.getElementById("settings.verticalScrollBarEnabled-settings.horizontalScrollBarEnabled"); + if (styleElement) { + styleElement.remove() + } + } + } + + if (webView.settings.disableVerticalScroll != newSettings.disableVerticalScroll) { + if (newSettings.disableVerticalScroll) { + const style = iframe.contentDocument?.createElement('style'); + if (style != null) { + style.id = "settings.disableVerticalScroll"; + style.innerHTML = "body { overflow-y: hidden; }"; + iframe.contentDocument?.head.append(style); + } + } else { + const styleElement = iframe.contentDocument?.getElementById("settings.disableVerticalScroll"); + if (styleElement) { + styleElement.remove() + } + } + } + + if (webView.settings.disableHorizontalScroll != newSettings.disableHorizontalScroll) { + if (newSettings.disableHorizontalScroll) { + const style = iframe.contentDocument?.createElement('style'); + if (style != null) { + style.id = "settings.disableHorizontalScroll"; + style.innerHTML = "body { overflow-x: hidden; }"; + iframe.contentDocument?.head.append(style); + } + } else { + const styleElement = iframe.contentDocument?.getElementById("settings.disableHorizontalScroll"); + if (styleElement) { + styleElement.remove() + } + } + } + + if (webView.settings.disableContextMenu != newSettings.disableContextMenu) { + if (newSettings.disableContextMenu) { + iframe.contentWindow?.addEventListener('contextmenu', webView.disableContextMenuHandler); + } else { + iframe.contentWindow?.removeEventListener('contextmenu', webView.disableContextMenuHandler); + } + } + } catch (e) { + console.log(e); + } + + webView.settings = newSettings; + }, + reload: function () { + var iframe = webView.iframe; + if (iframe != null && iframe.contentWindow != null) { + try { + iframe.contentWindow.location.reload(); + } catch (e) { + console.log(e); + iframe.contentWindow.location.href = iframe.src; + } + } + }, + goBack: function () { + var iframe = webView.iframe; + if (iframe != null) { + try { + iframe.contentWindow?.history.back(); + } catch (e) { + console.log(e); + } + } + }, + goForward: function () { + var iframe = webView.iframe; + if (iframe != null) { + try { + iframe.contentWindow?.history.forward(); + } catch (e) { + console.log(e); + } + } + }, + goBackOrForward: function (steps) { + var iframe = webView.iframe; + if (iframe != null) { + try { + iframe.contentWindow?.history.go(steps); + } catch (e) { + console.log(e); + } + } + }, + evaluateJavascript: function (source) { + const iframe = webView.iframe; + let result = null; + if (iframe != null) { + try { + result = JSON.stringify(iframe.contentWindow?.eval(source)); + } catch (e) { + } + } + return result; + }, + stopLoading: function () { + const iframe = webView.iframe; + if (iframe != null) { + try { + iframe.contentWindow?.stop(); + } catch (e) { + console.log(e); + } + } + }, + getUrl: function () { + const iframe = webView.iframe; + let url = iframe?.src; + try { + url = iframe?.contentWindow?.location.href; + } catch (e) { + console.log(e); + } + return url; + }, + getTitle: function () { + const iframe = webView.iframe; + let title = null; + try { + title = iframe?.contentDocument?.title; + } catch (e) { + console.log(e); + } + return title; + }, + injectJavascriptFileFromUrl: function (urlFile, scriptHtmlTagAttributes) { + const iframe = webView.iframe; + try { + const d = iframe?.contentDocument; + if (d == null) { + return; + } + const script = d.createElement('script'); + for (const key of Object.keys(scriptHtmlTagAttributes)) { + if (scriptHtmlTagAttributes[key] != null) { + // @ts-ignore + script[key] = scriptHtmlTagAttributes[key]; + } + } + if (script.id != null) { + script.onload = function () { + _nativeCommunication('onInjectedScriptLoaded', webView.viewId, [script.id]); + } + script.onerror = function () { + _nativeCommunication('onInjectedScriptError', webView.viewId, [script.id]); + } + } + script.src = urlFile; + if (d.body != null) { + d.body.appendChild(script); + } + } catch (e) { + console.log(e); + } + }, + injectCSSCode: function (source) { + const iframe = webView.iframe; + try { + const d = iframe?.contentDocument; + if (d == null) { + return; + } + const style = d.createElement('style'); + style.innerHTML = source; + if (d.head != null) { + d.head.appendChild(style); + } + } catch (e) { + console.log(e); + } + }, + injectCSSFileFromUrl: function (urlFile, cssLinkHtmlTagAttributes) { + const iframe = webView.iframe; + try { + const d = iframe?.contentDocument; + if (d == null) { + return; + } + const link = d.createElement('link'); + for (const key of Object.keys(cssLinkHtmlTagAttributes)) { + if (cssLinkHtmlTagAttributes[key] != null) { + // @ts-ignore + link[key] = cssLinkHtmlTagAttributes[key]; + } + } + link.type = 'text/css'; + var alternateStylesheet = ""; + if (cssLinkHtmlTagAttributes.alternateStylesheet) { + alternateStylesheet = "alternate "; + } + link.rel = alternateStylesheet + "stylesheet"; + link.href = urlFile; + if (d.head != null) { + d.head.appendChild(link); + } + } catch (e) { + console.log(e); + } + }, + scrollTo: function (x, y, animated) { + const iframe = webView.iframe; + try { + if (animated) { + iframe?.contentWindow?.scrollTo({top: y, left: x, behavior: 'smooth'}); + } else { + iframe?.contentWindow?.scrollTo(x, y); + } + } catch (e) { + console.log(e); + } + }, + scrollBy: function (x, y, animated) { + const iframe = webView.iframe; + try { + if (animated) { + iframe?.contentWindow?.scrollBy({top: y, left: x, behavior: 'smooth'}); + } else { + iframe?.contentWindow?.scrollBy(x, y); + } + } catch (e) { + console.log(e); + } + }, + printCurrentPage: function () { + const iframe = webView.iframe; + try { + iframe?.contentWindow?.print(); + } catch (e) { + console.log(e); + } + }, + getContentHeight: function () { + const iframe = webView.iframe; + try { + return iframe?.contentDocument?.documentElement.scrollHeight; + } catch (e) { + console.log(e); + } + return null; + }, + getContentWidth: function () { + const iframe = webView.iframe; + try { + return iframe?.contentDocument?.documentElement.scrollWidth; + } catch (e) { + console.log(e); + } + return null; + }, + getSelectedText: function () { + const iframe = webView.iframe; + try { + let txt; + const w = iframe?.contentWindow; + if (w == null) { + return null; + } + if (w.getSelection) { + txt = w.getSelection()?.toString(); + } else if (w.document.getSelection) { + txt = w.document.getSelection()?.toString(); + // @ts-ignore + } else if (w.document.selection) { + // @ts-ignore + txt = w.document.selection.createRange().text; + } + return txt; + } catch (e) { + console.log(e); + } + return null; + }, + getScrollX: function () { + const iframe = webView.iframe; + try { + return iframe?.contentWindow?.scrollX; + } catch (e) { + console.log(e); + } + return null; + }, + getScrollY: function () { + const iframe = webView.iframe; + try { + return iframe?.contentWindow?.scrollY; + } catch (e) { + console.log(e); + } + return null; + }, + isSecureContext: function () { + const iframe = webView.iframe; + try { + return iframe?.contentWindow?.isSecureContext ?? false; + } catch (e) { + console.log(e); + } + return false; + }, + canScrollVertically: function () { + const iframe = webView.iframe; + try { + return (iframe?.contentDocument?.body.scrollHeight ?? 0) > (iframe?.contentWindow?.innerHeight ?? 0); + } catch (e) { + console.log(e); + } + return false; + }, + canScrollHorizontally: function () { + const iframe = webView.iframe; + try { + return (iframe?.contentDocument?.body.scrollWidth ?? 0) > (iframe?.contentWindow?.innerWidth ?? 0); + } catch (e) { + console.log(e); + } + return false; + }, + getSize: function () { + const iframeContainer = webView.iframeContainer; + let width = 0.0; + let height = 0.0; + if (iframeContainer != null) { + if (iframeContainer.style.width != null && iframeContainer.style.width != '' && iframeContainer.style.width.indexOf('px') > 0) { + width = parseFloat(iframeContainer.style.width); + } + if (width == null || width == 0.0) { + width = iframeContainer.getBoundingClientRect().width; + } + if (iframeContainer.style.height != null && iframeContainer.style.height != '' && iframeContainer.style.height.indexOf('px') > 0) { + height = parseFloat(iframeContainer.style.height); + } + if (height == null || height == 0.0) { + height = iframeContainer.getBoundingClientRect().height; + } + } + return { + width: width, + height: height + }; + } + }; + + return webView; + }, + getCookieExpirationDate: function (timestamp: number) { + return (new Date(timestamp)).toUTCString(); + }, + nativeAsyncCommunication: function (method: string, viewId: number | string, args?: any[]) { + throw new Error("Method not implemented."); + }, + nativeSyncCommunication: function (method: string, viewId: number | string, args?: any[]) { + throw new Error("Method not implemented."); + }, + nativeCommunication: function (method: string, viewId: number | string, args?: any[]) { + try { + const result = window.flutter_inappwebview_plugin.nativeSyncCommunication(method, viewId, args); + return result != null ? JSON.parse(result) : null; + } catch (e1) { + try { + const promise = window.flutter_inappwebview_plugin.nativeAsyncCommunication(method, viewId, args); + return promise.then(function (result) { + return result != null ? JSON.parse(result) : null; + }); + } catch (e2) { + return null; + } + } + }, + }; + + let _nativeCommunication = window.flutter_inappwebview_plugin.nativeCommunication; +})(); \ No newline at end of file diff --git a/web_support/src/types.ts b/web_support/src/types.ts new file mode 100644 index 000000000..b455fa1b8 --- /dev/null +++ b/web_support/src/types.ts @@ -0,0 +1,75 @@ +export interface InAppWebViewSettings { + javaScriptBridgeEnabled?: boolean; + javaScriptBridgeOriginAllowList?: string[]; + javaScriptCanOpenWindowsAutomatically?: boolean; + verticalScrollBarEnabled?: boolean; + horizontalScrollBarEnabled?: boolean; + disableVerticalScroll?: boolean; + disableHorizontalScroll?: boolean; + disableContextMenu?: boolean; +} + +export interface InAppWebView { + viewId: any, + iframeId: string, + iframe?: HTMLIFrameElement | null, + iframeContainer?: HTMLDivElement | null, + isFullscreen: boolean, + documentTitle?: string | null, + functionMap: { + "window.open"?: any; + }, + settings: InAppWebViewSettings, + javaScriptBridgeEnabled: boolean, + disableContextMenuHandler: (event: Event) => boolean, + prepare: (settings: { [key: string]: any }) => void, + setSettings: (newSettings: InAppWebViewSettings) => void, + reload: () => void, + goBack: () => void, + goForward: () => void, + goBackOrForward: (steps: number) => void, + evaluateJavascript: (source: string) => any, + stopLoading: () => void, + getUrl: () => string | null | undefined, + getTitle: () => string | null | undefined, + injectJavascriptFileFromUrl: (urlFile: string, scriptHtmlTagAttributes: { [key: string]: any }) => void, + injectCSSCode: (source: string) => void, + injectCSSFileFromUrl: (urlFile: string, cssLinkHtmlTagAttributes: { [key: string]: any }) => void, + scrollTo: (x: number, y: number, animated: boolean) => void, + scrollBy: (x: number, y: number, animated: boolean) => void, + printCurrentPage: () => void, + getContentHeight: () => number | null | undefined, + getContentWidth: () => number | null | undefined, + getSelectedText: () => string | null | undefined, + getScrollX: () => number | null | undefined, + getScrollY: () => number | null | undefined, + isSecureContext: () => boolean, + canScrollVertically: () => boolean, + canScrollHorizontally: () => boolean, + getSize: () => { width: number, height: number } +} + +export interface InAppWebViewPlugin { + createFlutterInAppWebView: (viewId: number | string, iframe: HTMLIFrameElement, iframeContainer: HTMLDivElement, bridgeSecret: string) => InAppWebView, + getCookieExpirationDate: (timestamp: number) => string, + nativeAsyncCommunication: (method: string, viewId: number | string, args?: any[]) => Promise, + nativeSyncCommunication: (method: string, viewId: number | string, args?: any[]) => string, + nativeCommunication: (method: string, viewId: number | string, args?: any[]) => T, +} + +export interface JavaScriptBridgeHandler { + callHandler: (handlerName: string, ...args: any[]) => Promise +} + +export enum UserScriptInjectionTime { + AT_DOCUMENT_START = 0, + AT_DOCUMENT_END = 1 +} + +export interface UserScript { + allowedOriginRules?: string[] | null; + forMainFrameOnly: boolean; + groupName?: string | null; + injectionTime: UserScriptInjectionTime; + source: string; +} \ No newline at end of file diff --git a/web_support/tsconfig.json b/web_support/tsconfig.json new file mode 100644 index 000000000..7b7a9bd57 --- /dev/null +++ b/web_support/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "module": "commonjs", + "declaration": true, + "removeComments": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, + "target": "es2016", + "sourceMap": true, + "incremental": true, + "skipLibCheck": true, + "importHelpers": true, + "strictNullChecks": true, + "strict": true, + "resolveJsonModule": true, + "stripInternal": true + }, + "include": ["src"] +}