Commit 2811fce4 authored by Lorenzo Pichilli's avatar Lorenzo Pichilli

updated webview options classes, fixed debuggingEnabled, added...

updated webview options classes, fixed debuggingEnabled, added getTRexRunnerHtml and getTRexRunnerCss methods
parent 299042f8
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>
\ No newline at end of file
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="example/lib/main.dart" type="FlutterRunConfigurationType" factoryName="Flutter" singleton="false"> <configuration default="false" name="example/lib/main.dart" type="FlutterRunConfigurationType" factoryName="Flutter" singleton="false">
<option name="additionalArgs" value="--debug" />
<option name="filePath" value="$PROJECT_DIR$/example/lib/main.dart" /> <option name="filePath" value="$PROJECT_DIR$/example/lib/main.dart" />
<method v="2" /> <method v="2" />
</configuration> </configuration>
......
...@@ -15,38 +15,32 @@ ...@@ -15,38 +15,32 @@
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="9b41f7a2-a71e-4923-91fb-249d7815b3e7" name="Default" comment=""> <list default="true" id="9b41f7a2-a71e-4923-91fb-249d7815b3e7" name="Default" comment="">
<change afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowser.java" afterDir="false" /> <change afterPath="$PROJECT_DIR$/.idea/codeStyles/codeStyleConfig.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/example/assets/favicon.ico" afterDir="false" /> <change afterPath="$PROJECT_DIR$/lib/t_rex_runner/t-rex.css" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/CHANGELOG.md" beforeDir="false" afterPath="$PROJECT_DIR$/CHANGELOG.md" afterDir="false" /> <change beforePath="$PROJECT_DIR$/CHANGELOG.md" beforeDir="false" afterPath="$PROJECT_DIR$/CHANGELOG.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/android/build.gradle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/gradle.properties" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/AndroidManifest.xml" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/AndroidManifest.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ChromeCustomTabs/ChromeCustomTabsActivity.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ChromeCustomTabs/ChromeCustomTabsActivity.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerHandler.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerHandler.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerHandler.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/ContentBlocker/ContentBlockerHandler.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/CredentialDatabaseHandler.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/CredentialDatabaseHandler.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/FlutterWebView.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/FlutterWebView.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserActivity.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserActivity.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserFlutterPlugin.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserFlutterPlugin.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserOptions.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserOptions.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebChromeClient.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebChromeClient.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewClient.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewClient.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewClient.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewClient.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewOptions.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebViewOptions.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InputAwareWebView.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InputAwareWebView.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/JavaScriptBridgeInterface.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/JavaScriptBridgeInterface.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/MyCookieManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/MyCookieManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/Util.java" beforeDir="false" afterPath="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/Util.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/android/gradle.properties" beforeDir="false" afterPath="$PROJECT_DIR$/example/android/gradle.properties" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/assets/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/example/assets/index.html" afterDir="false" /> <change beforePath="$PROJECT_DIR$/example/assets/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/example/assets/index.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/Flutter/flutter_export_environment.sh" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/Flutter/flutter_export_environment.sh" afterDir="false" /> <change beforePath="$PROJECT_DIR$/example/ios/Podfile" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/Podfile" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/ios/Runner.xcodeproj/project.pbxproj" beforeDir="false" afterPath="$PROJECT_DIR$/example/ios/Runner.xcodeproj/project.pbxproj" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/lib/chrome_safari_example.screen.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/lib/chrome_safari_example.screen.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/lib/inline_example.screen.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/lib/inline_example.screen.dart" afterDir="false" /> <change beforePath="$PROJECT_DIR$/example/lib/inline_example.screen.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/lib/inline_example.screen.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/lib/test.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/lib/test.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/lib/webview_example.screen.dart" beforeDir="false" afterPath="$PROJECT_DIR$/example/lib/webview_example.screen.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/example/pubspec.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/example/pubspec.yaml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/example/pubspec.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/example/pubspec.yaml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ios/Classes/CustomeSchemeHandler.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/CustomeSchemeHandler.swift" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ios/Classes/FlutterWebViewController.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/FlutterWebViewController.swift" afterDir="false" /> <change beforePath="$PROJECT_DIR$/ios/Classes/FlutterWebViewController.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/FlutterWebViewController.swift" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ios/Classes/InAppWebView.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/InAppWebView.swift" afterDir="false" /> <change beforePath="$PROJECT_DIR$/ios/Classes/InAppWebView.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/InAppWebView.swift" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ios/Classes/SwiftFlutterPlugin.swift" beforeDir="false" afterPath="$PROJECT_DIR$/ios/Classes/SwiftFlutterPlugin.swift" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ios/flutter_inappbrowser.podspec" beforeDir="false" afterPath="$PROJECT_DIR$/ios/flutter_inappbrowser.podspec" afterDir="false" /> <change beforePath="$PROJECT_DIR$/ios/flutter_inappbrowser.podspec" beforeDir="false" afterPath="$PROJECT_DIR$/ios/flutter_inappbrowser.podspec" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/chrome_safari_browser.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/chrome_safari_browser.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/content_blocker.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/content_blocker.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/in_app_browser.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/in_app_browser.dart" afterDir="false" /> <change beforePath="$PROJECT_DIR$/lib/src/in_app_browser.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/in_app_browser.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/in_app_localhost_server.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/in_app_localhost_server.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/in_app_webview.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/in_app_webview.dart" afterDir="false" /> <change beforePath="$PROJECT_DIR$/lib/src/in_app_webview.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/in_app_webview.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/types.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/types.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/lib/src/webview_options.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/webview_options.dart" afterDir="false" /> <change beforePath="$PROJECT_DIR$/lib/src/webview_options.dart" beforeDir="false" afterPath="$PROJECT_DIR$/lib/src/webview_options.dart" afterDir="false" />
<change beforePath="$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/index.js" beforeDir="false" afterPath="$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/index.js" afterDir="false" /> <change beforePath="$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/index.js" beforeDir="false" afterPath="$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/index.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pubspec.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/pubspec.yaml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/pubspec.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/pubspec.yaml" afterDir="false" />
...@@ -69,29 +63,11 @@ ...@@ -69,29 +63,11 @@
<component name="ExecutionTargetManager" SELECTED_TARGET="Pixel_3_XL_API_24" /> <component name="ExecutionTargetManager" SELECTED_TARGET="Pixel_3_XL_API_24" />
<component name="FileEditorManager"> <component name="FileEditorManager">
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300"> <leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/CHANGELOG.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="336">
<caret line="28" column="24" selection-start-line="28" selection-start-column="24" selection-end-line="28" selection-end-column="24" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/index.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="423">
<caret line="49" column="46" selection-start-line="49" selection-start-column="46" selection-end-line="49" selection-end-column="46" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false"> <file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/lib/src/in_app_webview.dart"> <entry file="file://$PROJECT_DIR$/lib/src/in_app_webview.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="183"> <state relative-caret-position="251">
<caret line="114" column="101" selection-start-line="114" selection-start-column="87" selection-end-line="114" selection-end-column="101" /> <caret line="265" column="89" selection-start-line="261" selection-start-column="4" selection-end-line="265" selection-end-column="89" />
<folding> <folding>
<element signature="e#0#17#0" expanded="true" /> <element signature="e#0#17#0" expanded="true" />
</folding> </folding>
...@@ -100,42 +76,33 @@ ...@@ -100,42 +76,33 @@
</entry> </entry>
</file> </file>
<file pinned="false" current-in-tab="false"> <file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/lib/src/webview_options.dart"> <entry file="file://$PROJECT_DIR$/example/lib/inline_example.screen.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="142"> <state relative-caret-position="28">
<caret line="57" column="24" selection-start-line="57" selection-start-column="7" selection-end-line="57" selection-end-column="24" /> <caret line="94" column="32" selection-start-line="94" selection-start-column="16" selection-end-line="94" selection-end-column="32" />
<folding> <folding>
<element signature="e#0#17#0" expanded="true" /> <element signature="e#0#20#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
</file> </file>
<file pinned="false" current-in-tab="false"> <file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/example/assets/index.html"> <entry file="file://$PROJECT_DIR$/example/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="888"> <state relative-caret-position="131">
<caret line="79" column="11" selection-start-line="79" selection-start-column="11" selection-end-line="79" selection-end-column="11" /> <caret line="24" column="27" selection-start-line="24" selection-start-column="27" selection-end-line="24" selection-end-column="27" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-107">
<caret line="8" column="36" selection-start-line="8" selection-start-column="36" selection-end-line="8" selection-end-column="36" />
</state> </state>
</provider> </provider>
</entry> </entry>
</file> </file>
<file pinned="false" current-in-tab="true"> <file pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/example/lib/inline_example.screen.dart"> <entry file="file://$PROJECT_DIR$/lib/src/webview_options.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="294"> <state relative-caret-position="364">
<caret line="261" column="187" selection-start-line="259" selection-start-column="14" selection-end-line="261" selection-end-column="187" /> <caret line="81" column="43" selection-start-line="81" selection-start-column="43" selection-end-line="81" selection-end-column="43" />
<folding> <folding>
<element signature="e#0#20#0" expanded="true" /> <element signature="e#0#17#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
...@@ -153,36 +120,36 @@ ...@@ -153,36 +120,36 @@
</component> </component>
<component name="FindInProjectRecents"> <component name="FindInProjectRecents">
<findStrings> <findStrings>
<find>CER</find> <find>toggleErrorInformationPopup</find>
<find>ServerTrustChallenge</find> <find>error-information-popup-container</find>
<find>cONTENTMODE</find> <find>offline-spri</find>
<find>iOSInAppWebViewUserPreferredContentMode</find> <find>sprite</find>
<find>InAppWebViewUserPreferredContentMode</find> <find>icon-offline</find>
<find>serverCertificate</find> <find>ICON</find>
<find>onReceivedHttpAuthRequest</find> <find>loadImages</find>
<find>preferredContentMode</find> <find>RESOURCE_TEMPLATE_ID</find>
<find>print</find> <find>adjustDimensions</find>
<find>ConsoleMessageLevel</find> <find>outerContainerEl</find>
<find>onConsoleMessage</find> <find>ontouch</find>
<find>_findLocalPath</find> <find>fromVa</find>
<find>package</find> <find>ContentBlockerActionType</find>
<find>on</find>
<find>findAll</find>
<find>getFave</find>
<find>Uri</find>
<find>!= &quot;an</find>
<find>_channel</find>
<find>getHtml</find>
<find>url</find>
<find>getOptions</find> <find>getOptions</find>
<find>gestureR</find> <find>iOS</find>
<find>_dispose</find> <find>Ios</find>
<find>dispose</find> <find>initialOptions</find>
<find>Long</find> <find>initialOpti</find>
<find>custom</find> <find>Platform</find>
<find>scheme</find> <find>Platform.i</find>
<find>useOnLoadResource</find> <find>getOption</find>
<find>useShouldOverrideUrlLoading</find> <find>.toValue</find>
<find>fromValue(</find>
<find>?.toMap());</find>
<find>fromMap</find>
<find>setOptions</find>
<find>fromValue</find>
<find>List&lt;</find>
<find>debuggingEnabled</find>
<find>initialOp</find>
</findStrings> </findStrings>
<replaceStrings> <replaceStrings>
<replace>activity.getPreferences(0)</replace> <replace>activity.getPreferences(0)</replace>
...@@ -192,10 +159,12 @@ ...@@ -192,10 +159,12 @@
<replace>throwIsNotOpened</replace> <replace>throwIsNotOpened</replace>
<replace>ChannelManager</replace> <replace>ChannelManager</replace>
<replace>Function</replace> <replace>Function</replace>
<replace>?.toMap() ?? {});</replace>
</replaceStrings> </replaceStrings>
<dirStrings> <dirStrings>
<dir>$PROJECT_DIR$/example/android</dir> <dir>$PROJECT_DIR$/example/android</dir>
<dir>$PROJECT_DIR$/lib/src</dir> <dir>$PROJECT_DIR$/lib/src</dir>
<dir>$PROJECT_DIR$/lib</dir>
</dirStrings> </dirStrings>
</component> </component>
<component name="Git.Settings"> <component name="Git.Settings">
...@@ -204,11 +173,6 @@ ...@@ -204,11 +173,6 @@
<component name="IdeDocumentHistory"> <component name="IdeDocumentHistory">
<option name="CHANGED_PATHS"> <option name="CHANGED_PATHS">
<list> <list>
<option value="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutterwebview/InAppBrowserClient.java" />
<option value="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutterwebview/InAppBrowserDialog.java" />
<option value="$PROJECT_DIR$/android/settings.gradle" />
<option value="$PROJECT_DIR$/ios/Classes/InAppBrowser.m" />
<option value="$PROJECT_DIR$/ios/Classes/SwiftFlutterPlugin.swift" />
<option value="$PROJECT_DIR$/LICENSE" /> <option value="$PROJECT_DIR$/LICENSE" />
<option value="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserDialog.java" /> <option value="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserDialog.java" />
<option value="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserClient.java" /> <option value="$PROJECT_DIR$/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppBrowserClient.java" />
...@@ -231,30 +195,35 @@ ...@@ -231,30 +195,35 @@
<option value="$PROJECT_DIR$/lib/in_app_browser.dart" /> <option value="$PROJECT_DIR$/lib/in_app_browser.dart" />
<option value="$PROJECT_DIR$/lib/src/in_app_localhost_server.dart" /> <option value="$PROJECT_DIR$/lib/src/in_app_localhost_server.dart" />
<option value="$PROJECT_DIR$/lib/src/web_history.dart" /> <option value="$PROJECT_DIR$/lib/src/web_history.dart" />
<option value="$PROJECT_DIR$/example/lib/test.dart" />
<option value="$PROJECT_DIR$/lib/src/chrome_safari_browser.dart" />
<option value="$PROJECT_DIR$/example/ios/Runner/Info.plist" /> <option value="$PROJECT_DIR$/example/ios/Runner/Info.plist" />
<option value="$PROJECT_DIR$/example/lib/main.dart" /> <option value="$PROJECT_DIR$/example/lib/main.dart" />
<option value="$PROJECT_DIR$/lib/src/content_blocker.dart" />
<option value="$PROJECT_DIR$/example/lib/webview_example.screen.dart" />
<option value="$PROJECT_DIR$/lib/src/credentials_database.dart" /> <option value="$PROJECT_DIR$/lib/src/credentials_database.dart" />
<option value="$PROJECT_DIR$/lib/flutter_inappbrowser.dart" /> <option value="$PROJECT_DIR$/lib/flutter_inappbrowser.dart" />
<option value="$PROJECT_DIR$/ios/flutter_inappbrowser.podspec" /> <option value="$PROJECT_DIR$/ios/flutter_inappbrowser.podspec" />
<option value="$PROJECT_DIR$/lib/src/channel_manager.dart" /> <option value="$PROJECT_DIR$/lib/src/channel_manager.dart" />
<option value="$PROJECT_DIR$/lib/src/cookie_manager.dart" /> <option value="$PROJECT_DIR$/lib/src/cookie_manager.dart" />
<option value="$PROJECT_DIR$/lib/src/http_auth_credentials_database.dart" /> <option value="$PROJECT_DIR$/lib/src/http_auth_credentials_database.dart" />
<option value="$PROJECT_DIR$/example/lib/chrome_safari_example.screen.dart" />
<option value="$PROJECT_DIR$/lib/src/types.dart" />
<option value="$PROJECT_DIR$/CHANGELOG.md" />
<option value="$PROJECT_DIR$/lib/src/in_app_browser.dart" />
<option value="$PROJECT_DIR$/android/build.gradle" /> <option value="$PROJECT_DIR$/android/build.gradle" />
<option value="$PROJECT_DIR$/example/pubspec.yaml" /> <option value="$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/index.js" />
<option value="$PROJECT_DIR$/example/assets/index.html" />
<option value="$PROJECT_DIR$/lib/t_rex_runner/index.js" />
<option value="$PROJECT_DIR$/lib/t_rex_runner/index.css" />
<option value="$PROJECT_DIR$/lib/t_rex_runner/index.html" />
<option value="$PROJECT_DIR$/lib/t_rex_runner/t-rex.html" />
<option value="$PROJECT_DIR$/pubspec.yaml" /> <option value="$PROJECT_DIR$/pubspec.yaml" />
<option value="$PROJECT_DIR$/lib/t_rex_runner/t-rex.css" />
<option value="$PROJECT_DIR$/CHANGELOG.md" />
<option value="$PROJECT_DIR$/example/lib/test.dart" />
<option value="$PROJECT_DIR$/example/lib/webview_example.screen.dart" />
<option value="$PROJECT_DIR$/lib/src/content_blocker.dart" />
<option value="$PROJECT_DIR$/lib/src/types.dart" />
<option value="$PROJECT_DIR$/lib/src/in_app_webview.dart" /> <option value="$PROJECT_DIR$/lib/src/in_app_webview.dart" />
<option value="$PROJECT_DIR$/example/assets/index.html" /> <option value="$PROJECT_DIR$/lib/src/in_app_browser.dart" />
<option value="$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/index.js" /> <option value="$PROJECT_DIR$/lib/src/chrome_safari_browser.dart" />
<option value="$PROJECT_DIR$/lib/src/webview_options.dart" /> <option value="$PROJECT_DIR$/example/lib/chrome_safari_example.screen.dart" />
<option value="$PROJECT_DIR$/example/pubspec.yaml" />
<option value="$PROJECT_DIR$/example/lib/inline_example.screen.dart" /> <option value="$PROJECT_DIR$/example/lib/inline_example.screen.dart" />
<option value="$PROJECT_DIR$/lib/src/webview_options.dart" />
</list> </list>
</option> </option>
</component> </component>
...@@ -269,17 +238,6 @@ ...@@ -269,17 +238,6 @@
<foldersAlwaysOnTop value="true" /> <foldersAlwaysOnTop value="true" />
</navigator> </navigator>
<panes> <panes>
<pane id="Scope">
<subPane subId="Project Files">
<expand>
<path>
<item name="Root" type="cbb8eebc:String" user="Root" />
<item name="flutter_inappbrowser" type="cbb8eebc:String" user="flutter_inappbrowser" />
</path>
</expand>
<select />
</subPane>
</pane>
<pane id="AndroidView"> <pane id="AndroidView">
<subPane> <subPane>
<expand> <expand>
...@@ -309,6 +267,7 @@ ...@@ -309,6 +267,7 @@
<select /> <select />
</subPane> </subPane>
</pane> </pane>
<pane id="PackagesPane" />
<pane id="ProjectPane"> <pane id="ProjectPane">
<subPane> <subPane>
<expand> <expand>
...@@ -316,11 +275,6 @@ ...@@ -316,11 +275,6 @@
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" /> <item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" /> <item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
</path> </path>
<path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
<item name="android" type="462c0819:PsiDirectoryNode" />
</path>
<path> <path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" /> <item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" /> <item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
...@@ -330,7 +284,7 @@ ...@@ -330,7 +284,7 @@
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" /> <item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" /> <item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
<item name="example" type="462c0819:PsiDirectoryNode" /> <item name="example" type="462c0819:PsiDirectoryNode" />
<item name="assets" type="462c0819:PsiDirectoryNode" /> <item name="lib" type="462c0819:PsiDirectoryNode" />
</path> </path>
<path> <path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" /> <item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
...@@ -346,7 +300,8 @@ ...@@ -346,7 +300,8 @@
<path> <path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" /> <item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
<item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" /> <item name="flutter_inappbrowser" type="462c0819:PsiDirectoryNode" />
<item name="nodejs_server_test_auth_basic_and_ssl" type="462c0819:PsiDirectoryNode" /> <item name="lib" type="462c0819:PsiDirectoryNode" />
<item name="t_rex_runner" type="462c0819:PsiDirectoryNode" />
</path> </path>
<path> <path>
<item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" /> <item name="flutter_inappbrowser" type="b2602c69:ProjectViewProjectNode" />
...@@ -356,7 +311,17 @@ ...@@ -356,7 +311,17 @@
<select /> <select />
</subPane> </subPane>
</pane> </pane>
<pane id="PackagesPane" /> <pane id="Scope">
<subPane subId="Project Files">
<expand>
<path>
<item name="Root" type="cbb8eebc:String" user="Root" />
<item name="flutter_inappbrowser" type="cbb8eebc:String" user="flutter_inappbrowser" />
</path>
</expand>
<select />
</subPane>
</pane>
</panes> </panes>
</component> </component>
<component name="PropertiesComponent"> <component name="PropertiesComponent">
...@@ -372,15 +337,15 @@ ...@@ -372,15 +337,15 @@
<property name="project.structure.last.edited" value="SDK Location" /> <property name="project.structure.last.edited" value="SDK Location" />
<property name="project.structure.proportion" value="0.15" /> <property name="project.structure.proportion" value="0.15" />
<property name="project.structure.side.proportion" value="0.2" /> <property name="project.structure.side.proportion" value="0.2" />
<property name="settings.editor.selected.configurable" value="flutter.settings" /> <property name="settings.editor.selected.configurable" value="preferences.sourceCode.Other File Types" />
<property name="show.migrate.to.gradle.popup" value="false" /> <property name="show.migrate.to.gradle.popup" value="false" />
</component> </component>
<component name="RecentsManager"> <component name="RecentsManager">
<key name="MoveFile.RECENT_KEYS"> <key name="MoveFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/lib" />
<recent name="$PROJECT_DIR$/example/assets" /> <recent name="$PROJECT_DIR$/example/assets" />
<recent name="$PROJECT_DIR$/lib/src" /> <recent name="$PROJECT_DIR$/lib/src" />
<recent name="$PROJECT_DIR$/lib/in_app_browser.dart" /> <recent name="$PROJECT_DIR$/lib/in_app_browser.dart" />
<recent name="$PROJECT_DIR$/lib" />
<recent name="$PROJECT_DIR$/example/assets/images" /> <recent name="$PROJECT_DIR$/example/assets/images" />
</key> </key>
<key name="CopyFile.RECENT_KEYS"> <key name="CopyFile.RECENT_KEYS">
...@@ -507,10 +472,11 @@ ...@@ -507,10 +472,11 @@
</todo-panel> </todo-panel>
</component> </component>
<component name="ToolWindowManager"> <component name="ToolWindowManager">
<frame x="0" y="23" width="1920" height="1057" extended-state="6" /> <frame x="0" y="23" width="1920" height="1057" extended-state="0" />
<editor active="true" />
<layout> <layout>
<window_info content_ui="combo" id="Project" order="0" sideWeight="0.58835757" visible="true" weight="0.15867944" /> <window_info content_ui="combo" id="Project" order="0" sideWeight="0.6529745" visible="true" weight="0.15867944" />
<window_info id="Structure" order="1" sideWeight="0.4116424" side_tool="true" visible="true" weight="0.15867944" /> <window_info id="Structure" order="1" sideWeight="0.34702548" side_tool="true" weight="0.15867944" />
<window_info id="Designer" order="2" /> <window_info id="Designer" order="2" />
<window_info id="Build Variants" order="3" side_tool="true" /> <window_info id="Build Variants" order="3" side_tool="true" />
<window_info id="Captures" order="4" side_tool="true" weight="0.32936507" /> <window_info id="Captures" order="4" side_tool="true" weight="0.32936507" />
...@@ -520,7 +486,7 @@ ...@@ -520,7 +486,7 @@
<window_info id="Resources Explorer" order="8" /> <window_info id="Resources Explorer" order="8" />
<window_info anchor="bottom" id="Message" order="0" /> <window_info anchor="bottom" id="Message" order="0" />
<window_info anchor="bottom" id="Find" order="1" weight="0.32642487" /> <window_info anchor="bottom" id="Find" order="1" weight="0.32642487" />
<window_info active="true" anchor="bottom" id="Run" order="2" sideWeight="0.49307775" visible="true" weight="0.5015544" /> <window_info active="true" anchor="bottom" id="Run" order="2" sideWeight="0.49574015" visible="true" weight="0.5160622" />
<window_info anchor="bottom" id="Debug" order="3" weight="0.34196892" /> <window_info anchor="bottom" id="Debug" order="3" weight="0.34196892" />
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" /> <window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" /> <window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
...@@ -528,13 +494,14 @@ ...@@ -528,13 +494,14 @@
<window_info anchor="bottom" id="Android Profiler" order="7" show_stripe_button="false" /> <window_info anchor="bottom" id="Android Profiler" order="7" show_stripe_button="false" />
<window_info anchor="bottom" id="Event Log" order="8" sideWeight="0.50692225" side_tool="true" weight="0.38445595" /> <window_info anchor="bottom" id="Event Log" order="8" sideWeight="0.50692225" side_tool="true" weight="0.38445595" />
<window_info anchor="bottom" id="Version Control" order="9" weight="0.32953367" /> <window_info anchor="bottom" id="Version Control" order="9" weight="0.32953367" />
<window_info anchor="bottom" id="Terminal" order="10" sideWeight="0.49533224" weight="0.3968912" /> <window_info anchor="bottom" id="Terminal" order="10" sideWeight="0.49533224" weight="0.34507772" />
<window_info anchor="bottom" id="Logcat" order="11" weight="0.32953367" /> <window_info anchor="bottom" id="Logcat" order="11" weight="0.32953367" />
<window_info anchor="bottom" id="Messages" order="12" weight="0.226943" /> <window_info anchor="bottom" id="Messages" order="12" weight="0.3253886" />
<window_info anchor="bottom" id="Dependency Viewer" order="13" weight="0.32800853" /> <window_info anchor="bottom" id="Dependency Viewer" order="13" weight="0.32800853" />
<window_info anchor="bottom" id="Dart Analysis" order="14" sideWeight="0.4968051" weight="0.3253886" /> <window_info anchor="bottom" id="Dart Analysis" order="14" sideWeight="0.4968051" weight="0.3253886" />
<window_info anchor="bottom" id="Flutter Performance" order="15" side_tool="true" /> <window_info anchor="bottom" id="Flutter Performance" order="15" sideWeight="0.5042598" side_tool="true" weight="0.5160622" />
<window_info anchor="bottom" id="Build" order="16" /> <window_info anchor="bottom" id="Build" order="16" />
<window_info anchor="bottom" id="Thumbnails" order="17" weight="0.32953367" />
<window_info anchor="right" id="Commander" order="0" weight="0.4" /> <window_info anchor="right" id="Commander" order="0" weight="0.4" />
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" /> <window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" /> <window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
...@@ -549,6 +516,7 @@ ...@@ -549,6 +516,7 @@
</component> </component>
<component name="UnknownFeatures"> <component name="UnknownFeatures">
<option featureType="com.intellij.fileTypeFactory" implementationName="*.css" /> <option featureType="com.intellij.fileTypeFactory" implementationName="*.css" />
<option featureType="com.intellij.fileTypeFactory" implementationName="*.js" />
</component> </component>
<component name="VcsManagerConfiguration"> <component name="VcsManagerConfiguration">
<ignored-roots> <ignored-roots>
...@@ -556,353 +524,278 @@ ...@@ -556,353 +524,278 @@
</ignored-roots> </ignored-roots>
</component> </component>
<component name="editorHistoryManager"> <component name="editorHistoryManager">
<entry file="file://$USER_HOME$/flutter/packages/flutter/lib/src/widgets/platform_view.dart"> <entry file="file://$PROJECT_DIR$/lib/flutter_inappbrowser.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-182"> <state relative-caret-position="195">
<caret line="62" column="8" selection-start-line="62" selection-start-column="8" selection-end-line="62" selection-end-column="8" /> <caret line="32" column="47" selection-start-line="32" selection-start-column="47" selection-end-line="32" selection-end-column="47" />
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$USER_HOME$/flutter/packages/flutter/lib/src/widgets/framework.dart"> <entry file="file://$PROJECT_DIR$/example/assets/client1-crt.pem" />
<provider selected="true" editor-type-id="text-editor"> <entry file="file://$PROJECT_DIR$/example/assets/client1-crt.crt" />
<state relative-caret-position="125"> <entry file="file://$PROJECT_DIR$/pubspec.lock">
<caret line="779" column="15" selection-start-line="779" selection-start-column="15" selection-end-line="779" selection-end-column="15" /> <provider selected="true" editor-type-id="text-editor" />
</state>
</provider>
</entry> </entry>
<entry file="file://$USER_HOME$/flutter/packages/flutter/lib/src/widgets/container.dart"> <entry file="file://$PROJECT_DIR$/ios/flutter_inappbrowser.podspec">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-382"> <state relative-caret-position="315">
<caret line="253" column="2" selection-start-line="253" selection-start-column="2" selection-end-line="253" selection-end-column="2" /> <caret line="21" column="25" selection-start-line="21" selection-start-column="25" selection-end-line="21" selection-end-column="25" />
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/example/assets/css/style.css"> <entry file="file://$PROJECT_DIR$/.gitignore">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor" />
<state relative-caret-position="435">
<caret line="29" column="24" selection-start-line="29" selection-start-column="20" selection-end-line="29" selection-end-column="24" />
</state>
</provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/example/ios/Runner/Base.lproj/Main.storyboard"> <entry file="file://$PROJECT_DIR$/.packages">
<provider selected="true" editor-type-id="text-editor" /> <provider selected="true" editor-type-id="text-editor" />
</entry> </entry>
<entry file="file://$PROJECT_DIR$/ios/Classes/InAppWebView.swift"> <entry file="file://$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/.gitignore">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="426"> <state relative-caret-position="204">
<caret line="257" column="35" selection-start-line="257" selection-start-column="35" selection-end-line="257" selection-end-column="35" /> <caret line="42" column="12" selection-start-line="42" selection-start-column="5" selection-end-line="42" selection-end-column="12" />
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/android/src/main/AndroidManifest.xml"> <entry file="file://$PROJECT_DIR$/lib/src/channel_manager.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="180"> <state relative-caret-position="180">
<caret line="12" column="11" selection-start-line="12" selection-start-column="11" selection-end-line="12" selection-end-column="11" /> <caret line="12" column="9" selection-start-line="12" selection-start-column="9" selection-end-line="12" selection-end-column="9" />
</state> <folding>
</provider> <element signature="e#0#20#0" expanded="true" />
</entry> </folding>
<entry file="file://$PROJECT_DIR$/example/android/app/src/main/java/com/pichillilorenzo/flutterwebviewexample/MainActivity.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="60">
<caret line="6" column="13" selection-start-line="6" selection-start-column="13" selection-end-line="6" selection-end-column="13" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/android/app/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="960">
<caret line="64" column="74" selection-start-line="64" selection-start-column="74" selection-end-line="64" selection-end-column="74" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/android/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="195">
<caret line="13" column="16" selection-start-line="13" selection-start-column="16" selection-end-line="13" selection-end-column="16" />
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/lib/src/in_app_localhost_server.dart"> <entry file="file://$PROJECT_DIR$/lib/src/http_auth_credentials_database.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="60"> <state relative-caret-position="40">
<caret line="4" column="32" selection-start-line="4" selection-start-column="32" selection-end-line="4" selection-end-column="32" /> <caret line="21" column="9" selection-start-line="21" selection-start-column="9" selection-end-line="21" selection-end-column="9" />
<folding> <folding>
<element signature="e#0#17#0" expanded="true" /> <element signature="e#0#20#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/lib/src/web_history.dart" /> <entry file="file://$PROJECT_DIR$/lib/src/cookie_manager.dart">
<entry file="file://$PROJECT_DIR$/README.md">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="405"> <state relative-caret-position="198">
<caret line="27" column="3" lean-forward="true" selection-start-line="27" selection-start-column="3" selection-end-line="27" selection-end-column="3" /> <caret line="21" column="9" selection-start-line="21" selection-start-column="9" selection-end-line="21" selection-end-column="9" />
<folding> <folding>
<element signature="e#0#20#0" expanded="true" /> <element signature="e#0#20#0" expanded="true" />
<element signature="e#0#39#0" expanded="true" />
<element signature="e#0#39#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/example/lib/test.dart"> <entry file="file://$USER_HOME$/flutter/bin/cache/pkg/sky_engine/lib/core/uri.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-279"> <state relative-caret-position="15">
<caret line="8" column="38" selection-start-line="8" selection-start-column="38" selection-end-line="8" selection-end-column="38" /> <caret line="37" column="15" selection-start-line="37" selection-start-column="15" selection-end-line="37" selection-end-column="15" />
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$USER_HOME$/flutter/bin/cache/pkg/sky_engine/lib/core/list.dart"> <entry file="file://$PROJECT_DIR$/example/android/gradle.properties">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor" />
<state relative-caret-position="249">
<caret line="306" column="10" selection-start-line="306" selection-start-column="10" selection-end-line="306" selection-end-column="10" />
</state>
</provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/example/ios/Podfile"> <entry file="file://$PROJECT_DIR$/android/local.properties">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor" />
<state relative-caret-position="990">
<caret line="66" column="3" lean-forward="true" selection-start-line="66" selection-start-column="3" selection-end-line="66" selection-end-column="3" />
</state>
</provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/example/ios/Runner/Info.plist"> <entry file="file://$PROJECT_DIR$/android/gradle.properties" />
<entry file="file://$PROJECT_DIR$/android/build.gradle">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="60"> <state relative-caret-position="256">
<caret line="4" column="41" selection-start-line="4" selection-start-column="41" selection-end-line="4" selection-end-column="41" /> <caret line="25" selection-start-line="25" selection-end-line="25" />
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$USER_HOME$/flutter/bin/cache/pkg/sky_engine/lib/core/map.dart"> <entry file="file://$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/index.js">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="181"> <state relative-caret-position="733">
<caret line="303" column="4" selection-start-line="303" selection-start-column="4" selection-end-line="303" selection-end-column="4" /> <caret line="111" column="34" selection-start-line="111" selection-start-column="34" selection-end-line="111" selection-end-column="34" />
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/lib/src/content_blocker.dart"> <entry file="file://$USER_HOME$/flutter/bin/cache/pkg/sky_engine/lib/io/file.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="375"> <state relative-caret-position="-1206">
<caret line="25" column="34" selection-start-line="25" selection-start-column="34" selection-end-line="25" selection-end-column="34" /> <caret line="251" column="10" selection-start-line="251" selection-start-column="10" selection-end-line="251" selection-end-column="10" />
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$USER_HOME$/flutter/packages/flutter/lib/src/material/dialog.dart"> <entry file="file://$USER_HOME$/flutter/packages/flutter/lib/src/services/asset_bundle.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="307"> <state relative-caret-position="15">
<caret line="690" column="10" selection-start-line="690" selection-start-column="10" selection-end-line="690" selection-end-column="10" /> <caret line="65" column="17" selection-start-line="65" selection-start-column="17" selection-end-line="65" selection-end-column="17" />
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$USER_HOME$/flutter/bin/cache/pkg/sky_engine/lib/io/platform.dart"> <entry file="file://$PROJECT_DIR$/example/lib/main.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="233"> <state relative-caret-position="45">
<caret line="67" selection-start-line="67" selection-end-line="67" /> <caret line="12" column="23" selection-start-line="12" selection-start-column="3" selection-end-line="12" selection-end-column="23" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/lib/flutter_inappbrowser.dart"> <entry file="file://$PROJECT_DIR$/example/assets/index.html">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="195"> <state relative-caret-position="240">
<caret line="32" column="47" selection-start-line="32" selection-start-column="47" selection-end-line="32" selection-end-column="47" /> <caret line="34" column="87" selection-start-line="34" selection-start-column="87" selection-end-line="34" selection-end-column="87" />
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/lib/src/chrome_safari_browser.dart"> <entry file="file://$PROJECT_DIR$/lib/t_rex_runner/assets/novas-coisas.gif" />
<entry file="file://$PROJECT_DIR$/lib/t_rex_runner/assets/t-rex-runner-19janil.gif" />
<entry file="file://$PROJECT_DIR$/lib/t_rex_runner/assets/t-rex-runner-bot.gif" />
<entry file="file://$PROJECT_DIR$/lib/t_rex_runner/assets/hello-kugou.gif" />
<entry file="file://$PROJECT_DIR$/lib/t_rex_runner/assets/kumamon-runner.gif" />
<entry file="file://$PROJECT_DIR$/lib/t_rex_runner/assets/screenshot.gif" />
<entry file="file://$PROJECT_DIR$/lib/t_rex_runner/assets/default_200_percent/200-offline-sprite.png" />
<entry file="file://$PROJECT_DIR$/lib/t_rex_runner/assets/default_200_percent/200-error-offline.png" />
<entry file="file://$PROJECT_DIR$/lib/t_rex_runner/assets/default_200_percent/200-disabled.png" />
<entry file="file://$PROJECT_DIR$/lib/t_rex_runner/assets/offline-sprite-2x.png" />
<entry file="file://$PROJECT_DIR$/lib/t_rex_runner/assets/offline-sprite-1x.png" />
<entry file="file://$PROJECT_DIR$/lib/t_rex_runner/index.css" />
<entry file="file://$PROJECT_DIR$/lib/t_rex_runner/index.js" />
<entry file="file://$PROJECT_DIR$/lib/t_rex_runner/t-rex.html">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="225"> <state relative-caret-position="225">
<caret line="15" column="25" selection-start-line="15" selection-start-column="6" selection-end-line="15" selection-end-column="25" /> <caret line="15" column="38" selection-start-line="15" selection-start-column="38" selection-end-line="15" selection-end-column="38" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/example/assets/client1-crt.pem" /> <entry file="file://$PROJECT_DIR$/lib/t_rex_runner/t-rex.css">
<entry file="file://$PROJECT_DIR$/example/assets/client1-crt.crt" />
<entry file="file://$PROJECT_DIR$/pubspec.lock">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/ios/flutter_inappbrowser.podspec">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="315"> <state relative-caret-position="885">
<caret line="21" column="25" selection-start-line="21" selection-start-column="25" selection-end-line="21" selection-end-column="25" /> <caret line="59" selection-start-line="59" selection-end-line="59" />
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/.gitignore"> <entry file="file://$PROJECT_DIR$/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/.packages">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/.gitignore">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="204"> <state relative-caret-position="178">
<caret line="42" column="12" selection-start-line="42" selection-start-column="5" selection-end-line="42" selection-end-column="12" /> <caret line="28" column="58" selection-start-line="28" selection-start-column="58" selection-end-line="28" selection-end-column="58" />
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/example/lib/webview_example.screen.dart"> <entry file="file://$PROJECT_DIR$/example/lib/test.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="302"> <state relative-caret-position="827">
<caret line="73" lean-forward="true" selection-start-line="73" selection-end-line="73" /> <caret line="402" column="63" selection-start-line="402" selection-start-column="63" selection-end-line="402" selection-end-column="63" />
<folding> <folding>
<element signature="e#0#20#0" expanded="true" /> <element signature="e#0#16406#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/example/lib/main.dart"> <entry file="file://$PROJECT_DIR$/CHANGELOG.md">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="135"> <state relative-caret-position="408">
<caret line="9" column="7" selection-start-line="9" selection-start-column="7" selection-end-line="9" selection-end-column="7" /> <caret line="29" column="8" selection-start-line="29" selection-start-column="8" selection-end-line="29" selection-end-column="8" />
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/lib/src/channel_manager.dart"> <entry file="file://$USER_HOME$/flutter/bin/cache/dart-sdk/lib/collection/linked_hash_map.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="180"> <state relative-caret-position="137">
<caret line="12" column="9" selection-start-line="12" selection-start-column="9" selection-end-line="12" selection-end-column="9" /> <caret line="88" column="12" selection-start-line="88" selection-start-column="12" selection-end-line="88" selection-end-column="12" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/lib/src/http_auth_credentials_database.dart"> <entry file="file://$PROJECT_DIR$/example/lib/webview_example.screen.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="40"> <state relative-caret-position="465">
<caret line="21" column="9" selection-start-line="21" selection-start-column="9" selection-end-line="21" selection-end-column="9" /> <caret line="131" column="14" selection-start-line="131" selection-start-column="14" selection-end-line="131" selection-end-column="14" />
<folding> <folding>
<element signature="e#0#20#0" expanded="true" /> <element signature="e#0#20#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/lib/src/cookie_manager.dart"> <entry file="file://$PROJECT_DIR$/lib/src/content_blocker.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="198"> <state relative-caret-position="-206">
<caret line="21" column="9" selection-start-line="21" selection-start-column="9" selection-end-line="21" selection-end-column="9" /> <caret line="128" column="36" selection-start-line="128" selection-start-column="18" selection-end-line="128" selection-end-column="36" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/example/lib/chrome_safari_example.screen.dart"> <entry file="file://$PROJECT_DIR$/example/lib/chrome_safari_example.screen.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state> <state relative-caret-position="600">
<caret line="45" column="53" lean-forward="true" selection-start-line="45" selection-start-column="53" selection-end-line="45" selection-end-column="53" />
<folding> <folding>
<element signature="e#0#39#0" expanded="true" /> <element signature="e#0#39#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$USER_HOME$/flutter/bin/cache/pkg/sky_engine/lib/core/uri.dart"> <entry file="file://$PROJECT_DIR$/lib/src/chrome_safari_browser.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="15"> <state relative-caret-position="394">
<caret line="37" column="15" selection-start-line="37" selection-start-column="15" selection-end-line="37" selection-end-column="15" /> <caret line="94" column="5" selection-start-line="94" selection-start-column="5" selection-end-line="94" selection-end-column="5" />
<folding>
<element signature="e#0#20#0" expanded="true" />
</folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/lib/src/types.dart"> <entry file="file://$PROJECT_DIR$/lib/src/in_app_browser.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="235"> <state relative-caret-position="239">
<caret line="424" column="64" selection-start-line="424" selection-start-column="64" selection-end-line="424" selection-end-column="64" /> <caret line="287" column="5" selection-start-line="276" selection-start-column="4" selection-end-line="287" selection-end-column="5" />
<folding> <folding>
<element signature="e#0#20#0" expanded="true" /> <element signature="e#0#20#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/lib/src/in_app_browser.dart"> <entry file="file://$PROJECT_DIR$/lib/src/types.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="76"> <state relative-caret-position="215">
<caret line="268" column="65" selection-start-line="268" selection-start-column="65" selection-end-line="268" selection-end-column="65" /> <caret line="658" column="30" selection-start-line="658" selection-start-column="6" selection-end-line="658" selection-end-column="30" />
<folding> <folding>
<element signature="e#0#20#0" expanded="true" /> <element signature="e#0#20#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/example/android/gradle.properties"> <entry file="file://$PROJECT_DIR$/example/build/app/outputs/apk/debug/output.json">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/android/local.properties">
<provider selected="true" editor-type-id="text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/android/gradle.properties">
<provider selected="true" editor-type-id="text-editor" /> <provider selected="true" editor-type-id="text-editor" />
</entry> </entry>
<entry file="file://$PROJECT_DIR$/example/pubspec.yaml"> <entry file="file://$PROJECT_DIR$/example/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="141"> <state relative-caret-position="131">
<caret line="12" column="32" selection-start-line="12" selection-start-column="32" selection-end-line="12" selection-end-column="32" /> <caret line="24" column="27" selection-start-line="24" selection-start-column="27" selection-end-line="24" selection-end-column="27" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/pubspec.yaml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-107">
<caret line="8" column="36" selection-start-line="8" selection-start-column="36" selection-end-line="8" selection-end-column="36" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/android/build.gradle">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="256">
<caret line="25" selection-start-line="25" selection-end-line="25" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/CHANGELOG.md">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="336">
<caret line="28" column="24" selection-start-line="28" selection-start-column="24" selection-end-line="28" selection-end-column="24" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/example/assets/index.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="888">
<caret line="79" column="11" selection-start-line="79" selection-start-column="11" selection-end-line="79" selection-end-column="11" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/nodejs_server_test_auth_basic_and_ssl/index.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="423">
<caret line="49" column="46" selection-start-line="49" selection-start-column="46" selection-end-line="49" selection-end-column="46" />
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/lib/src/webview_options.dart"> <entry file="file://$PROJECT_DIR$/example/lib/inline_example.screen.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="142"> <state relative-caret-position="28">
<caret line="57" column="24" selection-start-line="57" selection-start-column="7" selection-end-line="57" selection-end-column="24" /> <caret line="94" column="32" selection-start-line="94" selection-start-column="16" selection-end-line="94" selection-end-column="32" />
<folding> <folding>
<element signature="e#0#17#0" expanded="true" /> <element signature="e#0#20#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/lib/src/in_app_webview.dart"> <entry file="file://$PROJECT_DIR$/lib/src/in_app_webview.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="183"> <state relative-caret-position="251">
<caret line="114" column="101" selection-start-line="114" selection-start-column="87" selection-end-line="114" selection-end-column="101" /> <caret line="265" column="89" selection-start-line="261" selection-start-column="4" selection-end-line="265" selection-end-column="89" />
<folding> <folding>
<element signature="e#0#17#0" expanded="true" /> <element signature="e#0#17#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/example/lib/inline_example.screen.dart"> <entry file="file://$PROJECT_DIR$/lib/src/webview_options.dart">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="294"> <state relative-caret-position="364">
<caret line="261" column="187" selection-start-line="259" selection-start-column="14" selection-end-line="261" selection-end-column="187" /> <caret line="81" column="43" selection-start-line="81" selection-start-column="43" selection-end-line="81" selection-end-column="43" />
<folding> <folding>
<element signature="e#0#20#0" expanded="true" /> <element signature="e#0#17#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
- Added `onReceivedServerTrustAuthRequest` and `onReceivedClientCertRequest` events to manage SSL requests - Added `onReceivedServerTrustAuthRequest` and `onReceivedClientCertRequest` events to manage SSL requests
- Added `onFindResultReceived` event, `findAllAsync`, `findNext` and `clearMatches` methods - Added `onFindResultReceived` event, `findAllAsync`, `findNext` and `clearMatches` methods
- Added `getHtml` method - Added `getHtml` method
- Fun: added `getTRexRunnerHtml` and `getTRexRunnerCss` methods to get html (with javascript) and css to recreate the Chromium's t-rex runner game
### BREAKING CHANGES ### BREAKING CHANGES
- Deleted `WebResourceRequest` class - Deleted `WebResourceRequest` class
......
...@@ -118,7 +118,7 @@ public class ContentBlockerHandler { ...@@ -118,7 +118,7 @@ public class ContentBlockerHandler {
if (!trigger.ifTopUrl.isEmpty()) { if (!trigger.ifTopUrl.isEmpty()) {
boolean matchFound = false; boolean matchFound = false;
for (String topUrl : trigger.ifTopUrl) { for (String topUrl : trigger.ifTopUrl) {
if (webViewUrl[0].equals(topUrl)) { if (webViewUrl[0].startsWith(topUrl)) {
matchFound = true; matchFound = true;
break; break;
} }
...@@ -128,7 +128,7 @@ public class ContentBlockerHandler { ...@@ -128,7 +128,7 @@ public class ContentBlockerHandler {
} }
if (!trigger.unlessTopUrl.isEmpty()) { if (!trigger.unlessTopUrl.isEmpty()) {
for (String topUrl : trigger.unlessTopUrl) for (String topUrl : trigger.unlessTopUrl)
if (webViewUrl[0].equals(topUrl)) if (webViewUrl[0].startsWith(topUrl))
return null; return null;
} }
......
...@@ -387,6 +387,9 @@ final public class InAppWebView extends InputAwareWebView { ...@@ -387,6 +387,9 @@ final public class InAppWebView extends InputAwareWebView {
if (newOptionsMap.get("javaScriptEnabled") != null && options.javaScriptEnabled != newOptions.javaScriptEnabled) if (newOptionsMap.get("javaScriptEnabled") != null && options.javaScriptEnabled != newOptions.javaScriptEnabled)
settings.setJavaScriptEnabled(newOptions.javaScriptEnabled); settings.setJavaScriptEnabled(newOptions.javaScriptEnabled);
if (newOptionsMap.get("debuggingEnabled") != null && options.debuggingEnabled != newOptions.debuggingEnabled && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
setWebContentsDebuggingEnabled(newOptions.debuggingEnabled);
if (newOptionsMap.get("javaScriptCanOpenWindowsAutomatically") != null && options.javaScriptCanOpenWindowsAutomatically != newOptions.javaScriptCanOpenWindowsAutomatically) if (newOptionsMap.get("javaScriptCanOpenWindowsAutomatically") != null && options.javaScriptCanOpenWindowsAutomatically != newOptions.javaScriptCanOpenWindowsAutomatically)
settings.setJavaScriptCanOpenWindowsAutomatically(newOptions.javaScriptCanOpenWindowsAutomatically); settings.setJavaScriptCanOpenWindowsAutomatically(newOptions.javaScriptCanOpenWindowsAutomatically);
......
...@@ -639,18 +639,18 @@ public class InAppWebViewClient extends WebViewClient { ...@@ -639,18 +639,18 @@ public class InAppWebViewClient extends WebViewClient {
Log.e(LOG_TAG, flutterResult.error); Log.e(LOG_TAG, flutterResult.error);
} }
else if (flutterResult.result != null) { else if (flutterResult.result != null) {
Map<String, String> res = (Map<String, String>) flutterResult.result; Map<String, Object> res = (Map<String, Object>) flutterResult.result;
WebResourceResponse response = null; WebResourceResponse response = null;
try { try {
response = webView.contentBlockerHandler.checkUrl(webView, url, res.get("content-type")); response = webView.contentBlockerHandler.checkUrl(webView, url, res.get("content-type").toString());
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
Log.e(LOG_TAG, e.getMessage()); Log.e(LOG_TAG, e.getMessage());
} }
if (response != null) if (response != null)
return response; return response;
byte[] data = Base64.decode(res.get("base64data"), Base64.DEFAULT); byte[] data = (byte[]) res.get("data");
return new WebResourceResponse(res.get("content-type"), res.get("content-encoding"), new ByteArrayInputStream(data)); return new WebResourceResponse(res.get("content-type").toString(), res.get("content-encoding").toString(), new ByteArrayInputStream(data));
} }
} }
......
...@@ -36,6 +36,11 @@ ...@@ -36,6 +36,11 @@
</p> </p>
</main> </main>
<!--<form method="POST" action="http://192.168.1.20:8082/test-post">
<input type="text" name="name" placeholder="name" value="Lorenzo">
<input type="submit" value="SEND">
</form>-->
<footer class="mastfoot mt-auto"> <footer class="mastfoot mt-auto">
<div class="inner"> <div class="inner">
<p>Cover template for <a target="_blank" href="https://getbootstrap.com/">Bootstrap</a>, by <a href="https://twitter.com/mdo">@mdo</a>.</p> <p>Cover template for <a target="_blank" href="https://getbootstrap.com/">Bootstrap</a>, by <a href="https://twitter.com/mdo">@mdo</a>.</p>
......
# Uncomment this line to define a global platform for your project # Uncomment this line to define a global platform for your project
# platform :ios, '9.0' platform :ios, '8.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency. # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true' ENV['COCOAPODS_DISABLE_STATS'] = 'true'
......
...@@ -267,7 +267,8 @@ ...@@ -267,7 +267,8 @@
); );
inputPaths = ( inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../.symlinks/flutter/ios-release/Flutter.framework", "${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework",
"${BUILT_PRODUCTS_DIR}/WKWebViewWithURLProtocol/WKWebViewWithURLProtocol.framework",
"${BUILT_PRODUCTS_DIR}/flutter_downloader/flutter_downloader.framework", "${BUILT_PRODUCTS_DIR}/flutter_downloader/flutter_downloader.framework",
"${BUILT_PRODUCTS_DIR}/flutter_inappbrowser/flutter_inappbrowser.framework", "${BUILT_PRODUCTS_DIR}/flutter_inappbrowser/flutter_inappbrowser.framework",
"${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework", "${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework",
...@@ -275,6 +276,7 @@ ...@@ -275,6 +276,7 @@
name = "[CP] Embed Pods Frameworks"; name = "[CP] Embed Pods Frameworks";
outputPaths = ( outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/WKWebViewWithURLProtocol.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_downloader.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_downloader.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_inappbrowser.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_inappbrowser.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework",
...@@ -296,7 +298,7 @@ ...@@ -296,7 +298,7 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
}; };
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
......
...@@ -36,10 +36,12 @@ class _ChromeSafariExampleScreenState extends State<ChromeSafariExampleScreen> { ...@@ -36,10 +36,12 @@ class _ChromeSafariExampleScreenState extends State<ChromeSafariExampleScreen> {
return new Center( return new Center(
child: new RaisedButton( child: new RaisedButton(
onPressed: () async { onPressed: () async {
await widget.browser.open("https://flutter.dev/", options: [ await widget.browser.open("https://flutter.dev/",
AndroidChromeCustomTabsOptions(addShareButton: false), options: ChromeSafariBrowserClassOptions(
iOSSafariOptions(barCollapsingEnabled: true) androidChromeCustomTabsOptions: AndroidChromeCustomTabsOptions(addShareButton: false),
]); iosSafariOptions: IosSafariOptions(barCollapsingEnabled: true)
)
);
}, },
child: Text("Open Chrome Safari Browser")), child: Text("Open Chrome Safari Browser")),
); );
......
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
...@@ -89,33 +90,34 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> { ...@@ -89,33 +90,34 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
//initialUrl: "https://192.168.1.20:4433/", //initialUrl: "https://192.168.1.20:4433/",
initialFile: "assets/index.html", initialFile: "assets/index.html",
initialHeaders: {}, initialHeaders: {},
initialOptions: [ initialOptions: InAppWebViewWidgetOptions(
InAppWebViewOptions( inAppWebViewOptions: InAppWebViewOptions(
debuggingEnabled: true,
//clearCache: true, //clearCache: true,
useShouldOverrideUrlLoading: true, useShouldOverrideUrlLoading: true,
useOnTargetBlank: true, useOnTargetBlank: true,
//useOnLoadResource: true, //useOnLoadResource: true,
useOnDownloadStart: true, useOnDownloadStart: true,
preferredContentMode: InAppWebViewUserPreferredContentMode.DESKTOP, //preferredContentMode: InAppWebViewUserPreferredContentMode.DESKTOP,
resourceCustomSchemes: ["my-special-custom-scheme"], resourceCustomSchemes: ["my-special-custom-scheme"],
/*contentBlockers: [ contentBlockers: [
ContentBlocker( ContentBlocker(
ContentBlockerTrigger(".*", ContentBlockerTrigger(".*",
resourceType: [ContentBlockerTriggerResourceType.IMAGE, ContentBlockerTriggerResourceType.STYLE_SHEET], resourceType: [ContentBlockerTriggerResourceType.IMAGE, ContentBlockerTriggerResourceType.STYLE_SHEET],
ifTopUrl: ["https://getbootstrap.com/"]), ifTopUrl: ["https://getbootstrap.com/"]),
ContentBlockerAction(ContentBlockerActionType.BLOCK) ContentBlockerAction(ContentBlockerActionType.BLOCK)
) )
]*/ ]
), ),
AndroidInAppWebViewOptions( androidInAppWebViewOptions: AndroidInAppWebViewOptions(
databaseEnabled: true, databaseEnabled: true,
appCacheEnabled: true, appCacheEnabled: true,
domStorageEnabled: true, domStorageEnabled: true,
geolocationEnabled: true, geolocationEnabled: true,
safeBrowsingEnabled: true, //safeBrowsingEnabled: true,
//blockNetworkImage: true, //blockNetworkImage: true,
), ),
], ),
onWebViewCreated: (InAppWebViewController controller) { onWebViewCreated: (InAppWebViewController controller) {
webView = controller; webView = controller;
...@@ -148,6 +150,28 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> { ...@@ -148,6 +150,28 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
}, },
onLoadError: (InAppWebViewController controller, String url, int code, String message) async { onLoadError: (InAppWebViewController controller, String url, int code, String message) async {
print("error $url: $code, $message"); print("error $url: $code, $message");
var tRexHtml = await controller.getTRexRunnerHtml();
var tRexCss = await controller.getTRexRunnerCss();
controller.loadData("""
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0,maximum-scale=1.0, user-scalable=no">
<style>${tRexCss}</style>
</head>
<body>
${tRexHtml}
<p>
URL ${url} failed to load.
</p>
<p>
Error: ${code}, ${message}
</p>
</body>
</html>
""");
}, },
onProgressChanged: onProgressChanged:
(InAppWebViewController controller, int progress) { (InAppWebViewController controller, int progress) {
...@@ -159,7 +183,7 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> { ...@@ -159,7 +183,7 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
print("override $url"); print("override $url");
controller.loadUrl(url); controller.loadUrl(url);
}, },
onLoadResource: (InAppWebViewController controller, WebResourceResponse response) { onLoadResource: (InAppWebViewController controller, LoadedResource response) {
print("Resource type: '"+response.initiatorType + "' started at: " + print("Resource type: '"+response.initiatorType + "' started at: " +
response.startTime.toString() + response.startTime.toString() +
"ms ---> duration: " + "ms ---> duration: " +
...@@ -187,8 +211,7 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> { ...@@ -187,8 +211,7 @@ class _InlineExampleScreenState extends State<InlineExampleScreen> {
onLoadResourceCustomScheme: (InAppWebViewController controller, String scheme, String url) async { onLoadResourceCustomScheme: (InAppWebViewController controller, String scheme, String url) async {
if (scheme == "my-special-custom-scheme") { if (scheme == "my-special-custom-scheme") {
var bytes = await rootBundle.load("assets/" + url.replaceFirst("my-special-custom-scheme://", "", 0)); var bytes = await rootBundle.load("assets/" + url.replaceFirst("my-special-custom-scheme://", "", 0));
var asBase64 = base64.encode(bytes.buffer.asUint8List()); var response = new CustomSchemeResponse(bytes.buffer.asUint8List(), "image/svg+xml", contentEnconding: "utf-8");
var response = new CustomSchemeResponse(asBase64, "image/svg+xml", contentEnconding: "utf-8");
return response; return response;
} }
return null; return null;
......
...@@ -400,7 +400,7 @@ class _MyAppState extends State<MyApp> { ...@@ -400,7 +400,7 @@ class _MyAppState extends State<MyApp> {
initialHeaders: { initialHeaders: {
}, },
initialOptions: [], initialOptions: InAppWebViewWidgetOptions(),
onWebViewCreated: (InAppWebViewController controller) { onWebViewCreated: (InAppWebViewController controller) {
webView = controller; webView = controller;
}, },
......
...@@ -47,7 +47,7 @@ class MyInappBrowser extends InAppBrowser { ...@@ -47,7 +47,7 @@ class MyInappBrowser extends InAppBrowser {
} }
@override @override
void onLoadResource(WebResourceResponse response) { void onLoadResource(LoadedResource response) {
print("Started at: " + print("Started at: " +
response.startTime.toString() + response.startTime.toString() +
"ms ---> duration: " + "ms ---> duration: " +
...@@ -121,12 +121,14 @@ class _WebviewExampleScreenState extends State<WebviewExampleScreen> { ...@@ -121,12 +121,14 @@ class _WebviewExampleScreenState extends State<WebviewExampleScreen> {
widget.browser.openFile( widget.browser.openFile(
"assets/index.html", "assets/index.html",
//url: "https://www.google.com/", //url: "https://www.google.com/",
options: [ options: InAppBrowserClassOptions(
InAppWebViewOptions( inAppWebViewWidgetOptions: InAppWebViewWidgetOptions(
inAppWebViewOptions: InAppWebViewOptions(
useShouldOverrideUrlLoading: true, useShouldOverrideUrlLoading: true,
useOnLoadResource: true, useOnLoadResource: true,
)
) )
] )
); );
}, },
child: Text("Open Webview Browser")), child: Text("Open Webview Browser")),
......
...@@ -20,13 +20,13 @@ class CustomeSchemeHandler : NSObject, WKURLSchemeHandler { ...@@ -20,13 +20,13 @@ class CustomeSchemeHandler : NSObject, WKURLSchemeHandler {
} }
else if (result as? NSObject) == FlutterMethodNotImplemented {} else if (result as? NSObject) == FlutterMethodNotImplemented {}
else { else {
let json: [String: String] let json: [String: Any]
if let r = result { if let r = result {
json = r as! [String: String] json = r as! [String: Any]
let urlResponse = URLResponse(url: url, mimeType: json["content-type"], expectedContentLength: -1, textEncodingName: json["content-encoding"]) let urlResponse = URLResponse(url: url, mimeType: json["content-type"] as! String, expectedContentLength: -1, textEncodingName: json["content-encoding"] as! String)
let data = Data(base64Encoded: json["base64data"]!, options: .ignoreUnknownCharacters) let data = json["data"] as! FlutterStandardTypedData
urlSchemeTask.didReceive(urlResponse) urlSchemeTask.didReceive(urlResponse)
urlSchemeTask.didReceive(data!) urlSchemeTask.didReceive(data.data)
urlSchemeTask.didFinish() urlSchemeTask.didFinish()
} }
} }
......
...@@ -14,9 +14,10 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView { ...@@ -14,9 +14,10 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
var webView: InAppWebView? var webView: InAppWebView?
var viewId: Int64 = 0 var viewId: Int64 = 0
var channel: FlutterMethodChannel? var channel: FlutterMethodChannel?
init(registrar: FlutterPluginRegistrar, withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: NSDictionary) { init(registrar: FlutterPluginRegistrar, withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: NSDictionary) {
super.init() super.init()
self.registrar = registrar self.registrar = registrar
self.viewId = viewId self.viewId = viewId
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
import Flutter import Flutter
import Foundation import Foundation
import WebKit import WebKit
import WKWebViewWithURLProtocol
func currentTimeInMilliSeconds() -> Int64 { func currentTimeInMilliSeconds() -> Int64 {
let currentDate = Date() let currentDate = Date()
...@@ -242,6 +243,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi ...@@ -242,6 +243,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
static var credentialsProposed: [URLCredential] = [] static var credentialsProposed: [URLCredential] = []
init(frame: CGRect, configuration: WKWebViewConfiguration, IABController: InAppBrowserWebViewController?, IAWController: FlutterWebViewController?) { init(frame: CGRect, configuration: WKWebViewConfiguration, IABController: InAppBrowserWebViewController?, IAWController: FlutterWebViewController?) {
super.init(frame: frame, configuration: configuration) super.init(frame: frame, configuration: configuration)
self.IABController = IABController self.IABController = IABController
self.IAWController = IAWController self.IAWController = IAWController
......
...@@ -47,6 +47,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin { ...@@ -47,6 +47,7 @@ public class SwiftFlutterPlugin: NSObject, FlutterPlugin {
public init(with registrar: FlutterPluginRegistrar) { public init(with registrar: FlutterPluginRegistrar) {
super.init() super.init()
self.registrar = registrar self.registrar = registrar
self.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappbrowser", binaryMessenger: registrar.messenger()) self.channel = FlutterMethodChannel(name: "com.pichillilorenzo/flutter_inappbrowser", binaryMessenger: registrar.messenger())
registrar.addMethodCallDelegate(self, channel: channel!) registrar.addMethodCallDelegate(self, channel: channel!)
......
...@@ -17,7 +17,7 @@ A new Flutter plugin. ...@@ -17,7 +17,7 @@ A new Flutter plugin.
s.public_header_files = 'Classes/**/*.h' s.public_header_files = 'Classes/**/*.h'
s.dependency 'Flutter' s.dependency 'Flutter'
s.platform = '8.0'
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' }
s.swift_version = '5.0' s.swift_version = '5.0'
s.dependency "WKWebViewWithURLProtocol"
end end
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_inappbrowser/src/webview_options.dart';
import 'types.dart'; import 'types.dart';
import 'channel_manager.dart'; import 'channel_manager.dart';
...@@ -70,19 +70,29 @@ class ChromeSafariBrowser { ...@@ -70,19 +70,29 @@ class ChromeSafariBrowser {
///- __preferredControlTintColor__: Set the custom color of the control buttons on the navigation bar and the toolbar. ///- __preferredControlTintColor__: Set the custom color of the control buttons on the navigation bar and the toolbar.
///- __presentationStyle__: Set the custom modal presentation style when presenting the WebView. The default value is `0 //fullscreen`. See [UIModalPresentationStyle](https://developer.apple.com/documentation/uikit/uimodalpresentationstyle) for all the available styles. ///- __presentationStyle__: Set the custom modal presentation style when presenting the WebView. The default value is `0 //fullscreen`. See [UIModalPresentationStyle](https://developer.apple.com/documentation/uikit/uimodalpresentationstyle) for all the available styles.
///- __transitionStyle__: Set to the custom transition style when presenting the WebView. The default value is `0 //crossDissolve`. See [UIModalTransitionStyle](https://developer.apple.com/documentation/uikit/uimodaltransitionStyle) for all the available styles. ///- __transitionStyle__: Set to the custom transition style when presenting the WebView. The default value is `0 //crossDissolve`. See [UIModalTransitionStyle](https://developer.apple.com/documentation/uikit/uimodaltransitionStyle) for all the available styles.
Future<void> open(String url, {List<ChromeSafariBrowserOptions> options = const [], Map<String, String> headersFallback = const {}, List<BrowserOptions> optionsFallback = const []}) async { Future<void> open(String url, {ChromeSafariBrowserClassOptions options, Map<String, String> headersFallback = const {}, InAppBrowserClassOptions optionsFallback}) async {
assert(url != null && url.isNotEmpty); assert(url != null && url.isNotEmpty);
this.throwIsAlreadyOpened(message: 'Cannot open $url!'); this.throwIsAlreadyOpened(message: 'Cannot open $url!');
Map<String, dynamic> optionsMap = {}; Map<String, dynamic> optionsMap = {};
options.forEach((webViewOption) { if (Platform.isAndroid)
optionsMap.addAll(webViewOption.toMap()); optionsMap.addAll(options.androidChromeCustomTabsOptions?.toMap() ?? {});
}); else if (Platform.isIOS)
optionsMap.addAll(options.iosSafariOptions?.toMap() ?? {});
Map<String, dynamic> optionsFallbackMap = {}; Map<String, dynamic> optionsFallbackMap = {};
optionsFallback.forEach((webViewOption) { if (optionsFallback != null) {
optionsFallbackMap.addAll(webViewOption.toMap()); optionsFallbackMap.addAll(optionsFallback.inAppBrowserOptions?.toMap() ?? {});
}); optionsFallbackMap.addAll(optionsFallback.inAppWebViewWidgetOptions?.inAppWebViewOptions?.toMap() ?? {});
if (Platform.isAndroid) {
optionsFallbackMap.addAll(optionsFallback.androidInAppBrowserOptions?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback.inAppWebViewWidgetOptions?.androidInAppWebViewOptions?.toMap() ?? {});
}
else if (Platform.isIOS) {
optionsFallbackMap.addAll(optionsFallback.iosInAppBrowserOptions?.toMap() ?? {});
optionsFallbackMap.addAll(optionsFallback.inAppWebViewWidgetOptions?.iosInAppWebViewOptions?.toMap() ?? {});
}
}
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid); args.putIfAbsent('uuid', () => uuid);
......
...@@ -10,11 +10,26 @@ class ContentBlocker { ...@@ -10,11 +10,26 @@ class ContentBlocker {
"action": action.toMap() "action": action.toMap()
}; };
} }
static ContentBlocker fromMap(Map<dynamic, Map<dynamic, dynamic>> map) {
return ContentBlocker(
ContentBlockerTrigger.fromMap(
Map<String, dynamic>.from(map["trigger"])
),
ContentBlockerAction.fromMap(
Map<String, dynamic>.from(map["action"])
)
);
}
} }
class ContentBlockerTriggerResourceType { class ContentBlockerTriggerResourceType {
final String _value; final String _value;
const ContentBlockerTriggerResourceType._internal(this._value); const ContentBlockerTriggerResourceType._internal(this._value);
static ContentBlockerTriggerResourceType fromValue(String value) {
return (["document", "image", "LINK", "style-sheet", "script", "font",
"media", "svg-document", "raw"].contains(value)) ? ContentBlockerTriggerResourceType._internal(value) : null;
}
toValue() => _value; toValue() => _value;
static const DOCUMENT = const ContentBlockerTriggerResourceType._internal('document'); static const DOCUMENT = const ContentBlockerTriggerResourceType._internal('document');
...@@ -30,6 +45,9 @@ class ContentBlockerTriggerResourceType { ...@@ -30,6 +45,9 @@ class ContentBlockerTriggerResourceType {
class ContentBlockerTriggerLoadType { class ContentBlockerTriggerLoadType {
final String _value; final String _value;
const ContentBlockerTriggerLoadType._internal(this._value); const ContentBlockerTriggerLoadType._internal(this._value);
static ContentBlockerTriggerLoadType fromValue(String value) {
return (["first-party", "third-party"].contains(value)) ? ContentBlockerTriggerLoadType._internal(value) : null;
}
toValue() => _value; toValue() => _value;
static const FIRST_PARTY = const ContentBlockerTriggerLoadType._internal('first-party'); static const FIRST_PARTY = const ContentBlockerTriggerLoadType._internal('first-party');
...@@ -90,11 +108,40 @@ class ContentBlockerTrigger { ...@@ -90,11 +108,40 @@ class ContentBlockerTrigger {
return map; return map;
} }
static ContentBlockerTrigger fromMap(Map<String, dynamic> map) {
List<ContentBlockerTriggerResourceType> resourceType = [];
List<ContentBlockerTriggerLoadType> loadType = [];
List<String> resourceTypeStringList = List<String>.from(map["resource-type"] ?? []);
resourceTypeStringList.forEach((type) {
resourceType.add(ContentBlockerTriggerResourceType.fromValue(type));
});
List<String> loadTypeStringList = List<String>.from(map["load-type"] ?? []);
loadTypeStringList.forEach((type) {
loadType.add(ContentBlockerTriggerLoadType.fromValue(type));
});
return ContentBlockerTrigger(
map["url-filter"],
urlFilterIsCaseSensitive: map["url-filter-is-case-sensitive"],
ifDomain: List<String>.from(map["if-domain"] ?? []),
unlessDomain: List<String>.from(map["unless-domain"] ?? []),
resourceType: resourceType,
loadType: loadType,
ifTopUrl: List<String>.from(map["if-top-url"] ?? []),
unlessTopUrl: List<String>.from(map["unless-top-url"] ?? [])
);
}
} }
class ContentBlockerActionType { class ContentBlockerActionType {
final String _value; final String _value;
const ContentBlockerActionType._internal(this._value); const ContentBlockerActionType._internal(this._value);
static ContentBlockerActionType fromValue(String value) {
return (["block", "css-display-none", "make-https"].contains(value)) ? ContentBlockerActionType._internal(value) : null;
}
toValue() => _value; toValue() => _value;
static const BLOCK = const ContentBlockerActionType._internal('block'); static const BLOCK = const ContentBlockerActionType._internal('block');
...@@ -127,4 +174,11 @@ class ContentBlockerAction { ...@@ -127,4 +174,11 @@ class ContentBlockerAction {
return map; return map;
} }
static ContentBlockerAction fromMap(Map<String, dynamic> map) {
return ContentBlockerAction(
ContentBlockerActionType.fromValue(map["type"]),
selector: map["selector"]
);
}
} }
\ No newline at end of file
import 'dart:async'; import 'dart:async';
import 'dart:collection'; import 'dart:collection';
import 'dart:io';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_inappbrowser/src/webview_options.dart'; import 'package:flutter_inappbrowser/src/webview_options.dart';
...@@ -102,14 +103,22 @@ class InAppBrowser { ...@@ -102,14 +103,22 @@ class InAppBrowser {
/// - __allowsInlineMediaPlayback__: Set to `true` to allow HTML5 media playback to appear inline within the screen layout, using browser-supplied controls rather than native controls. For this to work, add the `webkit-playsinline` attribute to any `<video>` elements. The default value is `false`. /// - __allowsInlineMediaPlayback__: Set to `true` to allow HTML5 media playback to appear inline within the screen layout, using browser-supplied controls rather than native controls. For this to work, add the `webkit-playsinline` attribute to any `<video>` elements. The default value is `false`.
/// - __allowsPictureInPictureMediaPlayback__: Set to `true` to allow HTML5 videos play picture-in-picture. The default value is `true`. /// - __allowsPictureInPictureMediaPlayback__: Set to `true` to allow HTML5 videos play picture-in-picture. The default value is `true`.
/// - __spinner__: Set to `false` to hide the spinner when the WebView is loading a page. The default value is `true`. /// - __spinner__: Set to `false` to hide the spinner when the WebView is loading a page. The default value is `true`.
Future<void> open({String url = "about:blank", Map<String, String> headers = const {}, List<BrowserOptions> options = const []}) async { Future<void> open({String url = "about:blank", Map<String, String> headers = const {}, InAppBrowserClassOptions options}) async {
assert(url != null && url.isNotEmpty); assert(url != null && url.isNotEmpty);
this.throwIsAlreadyOpened(message: 'Cannot open $url!'); this.throwIsAlreadyOpened(message: 'Cannot open $url!');
Map<String, dynamic> optionsMap = {}; Map<String, dynamic> optionsMap = {};
options.forEach((webViewOption) {
optionsMap.addAll(webViewOption.toMap()); optionsMap.addAll(options.inAppBrowserOptions?.toMap() ?? {});
}); optionsMap.addAll(options.inAppWebViewWidgetOptions?.inAppWebViewOptions?.toMap() ?? {});
if (Platform.isAndroid) {
optionsMap.addAll(options.androidInAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.androidInAppWebViewOptions?.toMap() ?? {});
}
else if (Platform.isIOS) {
optionsMap.addAll(options.iosInAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.iosInAppWebViewOptions?.toMap() ?? {});
}
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid); args.putIfAbsent('uuid', () => uuid);
...@@ -140,7 +149,7 @@ class InAppBrowser { ...@@ -140,7 +149,7 @@ class InAppBrowser {
/// uses-material-design: true /// uses-material-design: true
/// ///
/// assets: /// assets:
/// - assets/index.html /// - assets/t-rex.html
/// - assets/css/ /// - assets/css/
/// - assets/images/ /// - assets/images/
/// ///
...@@ -149,17 +158,25 @@ class InAppBrowser { ...@@ -149,17 +158,25 @@ class InAppBrowser {
///Example of a `main.dart` file: ///Example of a `main.dart` file:
///```dart ///```dart
///... ///...
///inAppBrowser.openFile("assets/index.html"); ///inAppBrowser.openFile("assets/t-rex.html");
///... ///...
///``` ///```
Future<void> openFile(String assetFilePath, {Map<String, String> headers = const {}, List<BrowserOptions> options = const []}) async { Future<void> openFile(String assetFilePath, {Map<String, String> headers = const {}, InAppBrowserClassOptions options}) async {
assert(assetFilePath != null && assetFilePath.isNotEmpty); assert(assetFilePath != null && assetFilePath.isNotEmpty);
this.throwIsAlreadyOpened(message: 'Cannot open $assetFilePath!'); this.throwIsAlreadyOpened(message: 'Cannot open $assetFilePath!');
Map<String, dynamic> optionsMap = {}; Map<String, dynamic> optionsMap = {};
options.forEach((webViewOption) {
optionsMap.addAll(webViewOption.toMap()); optionsMap.addAll(options.inAppBrowserOptions?.toMap() ?? {});
}); optionsMap.addAll(options.inAppWebViewWidgetOptions?.inAppWebViewOptions?.toMap() ?? {});
if (Platform.isAndroid) {
optionsMap.addAll(options.androidInAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.androidInAppWebViewOptions?.toMap() ?? {});
}
else if (Platform.isIOS) {
optionsMap.addAll(options.iosInAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.iosInAppWebViewOptions?.toMap() ?? {});
}
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid); args.putIfAbsent('uuid', () => uuid);
...@@ -176,13 +193,21 @@ class InAppBrowser { ...@@ -176,13 +193,21 @@ class InAppBrowser {
///Opens a new [InAppBrowser] instance with [data] as a content, using [baseUrl] as the base URL for it. ///Opens a new [InAppBrowser] instance with [data] as a content, using [baseUrl] as the base URL for it.
///The [mimeType] parameter specifies the format of the data. ///The [mimeType] parameter specifies the format of the data.
///The [encoding] parameter specifies the encoding of the data. ///The [encoding] parameter specifies the encoding of the data.
Future<void> openData(String data, {String mimeType = "text/html", String encoding = "utf8", String baseUrl = "about:blank", List<BrowserOptions> options = const []}) async { Future<void> openData(String data, {String mimeType = "text/html", String encoding = "utf8", String baseUrl = "about:blank", InAppBrowserClassOptions options}) async {
assert(data != null); assert(data != null);
Map<String, dynamic> optionsMap = {}; Map<String, dynamic> optionsMap = {};
options.forEach((webViewOption) {
optionsMap.addAll(webViewOption.toMap()); optionsMap.addAll(options.inAppBrowserOptions?.toMap() ?? {});
}); optionsMap.addAll(options.inAppWebViewWidgetOptions?.inAppWebViewOptions?.toMap() ?? {});
if (Platform.isAndroid) {
optionsMap.addAll(options.androidInAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.androidInAppWebViewOptions?.toMap() ?? {});
}
else if (Platform.isIOS) {
optionsMap.addAll(options.iosInAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.iosInAppWebViewOptions?.toMap() ?? {});
}
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid); args.putIfAbsent('uuid', () => uuid);
...@@ -246,13 +271,21 @@ class InAppBrowser { ...@@ -246,13 +271,21 @@ class InAppBrowser {
} }
///Sets the [InAppBrowser] options with the new [options] and evaluates them. ///Sets the [InAppBrowser] options with the new [options] and evaluates them.
Future<void> setOptions(List<BrowserOptions> options) async { Future<void> setOptions(InAppBrowserClassOptions options) async {
this.throwIsNotOpened(); this.throwIsNotOpened();
Map<String, dynamic> optionsMap = {}; Map<String, dynamic> optionsMap = {};
options.forEach((webViewOption) {
optionsMap.addAll(webViewOption.toMap()); optionsMap.addAll(options.inAppBrowserOptions?.toMap() ?? {});
}); optionsMap.addAll(options.inAppWebViewWidgetOptions?.inAppWebViewOptions?.toMap() ?? {});
if (Platform.isAndroid) {
optionsMap.addAll(options.androidInAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.androidInAppWebViewOptions?.toMap() ?? {});
}
else if (Platform.isIOS) {
optionsMap.addAll(options.iosInAppBrowserOptions?.toMap() ?? {});
optionsMap.addAll(options.inAppWebViewWidgetOptions?.iosInAppWebViewOptions?.toMap() ?? {});
}
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid); args.putIfAbsent('uuid', () => uuid);
...@@ -262,15 +295,29 @@ class InAppBrowser { ...@@ -262,15 +295,29 @@ class InAppBrowser {
} }
///Gets the current [InAppBrowser] options as a `Map`. Returns `null` if the options are not setted yet. ///Gets the current [InAppBrowser] options as a `Map`. Returns `null` if the options are not setted yet.
Future<Map<String, dynamic>> getOptions() async { Future<InAppBrowserClassOptions> getOptions() async {
this.throwIsNotOpened(); this.throwIsNotOpened();
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid); args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('optionsType', () => "InAppBrowserOptions"); args.putIfAbsent('optionsType', () => "InAppBrowserOptions");
InAppBrowserClassOptions inAppBrowserClassOptions = InAppBrowserClassOptions();
Map<dynamic, dynamic> options = await ChannelManager.channel.invokeMethod('getOptions', args); Map<dynamic, dynamic> options = await ChannelManager.channel.invokeMethod('getOptions', args);
if (options != null) if (options != null) {
options = options.cast<String, dynamic>(); options = options.cast<String, dynamic>();
return options; inAppBrowserClassOptions.inAppBrowserOptions = InAppBrowserOptions.fromMap(options);
inAppBrowserClassOptions.inAppWebViewWidgetOptions.inAppWebViewOptions = InAppWebViewOptions.fromMap(options);
if (Platform.isAndroid) {
inAppBrowserClassOptions.androidInAppBrowserOptions = AndroidInAppBrowserOptions.fromMap(options);
inAppBrowserClassOptions.inAppWebViewWidgetOptions.androidInAppWebViewOptions = AndroidInAppWebViewOptions.fromMap(options);
}
else if (Platform.isIOS) {
inAppBrowserClassOptions.iosInAppBrowserOptions = IosInAppBrowserOptions.fromMap(options);
inAppBrowserClassOptions.inAppWebViewWidgetOptions.iosInAppWebViewOptions = IosInAppWebViewOptions.fromMap(options);
}
}
return inAppBrowserClassOptions;
} }
///Returns `true` if the [InAppBrowser] instance is opened, otherwise `false`. ///Returns `true` if the [InAppBrowser] instance is opened, otherwise `false`.
...@@ -323,7 +370,7 @@ class InAppBrowser { ...@@ -323,7 +370,7 @@ class InAppBrowser {
///Event fires when the [InAppBrowser] webview loads a resource. ///Event fires when the [InAppBrowser] webview loads a resource.
/// ///
///**NOTE**: In order to be able to listen this event, you need to set `useOnLoadResource` option to `true`. ///**NOTE**: In order to be able to listen this event, you need to set `useOnLoadResource` option to `true`.
void onLoadResource(WebResourceResponse response) { void onLoadResource(LoadedResource resource) {
} }
......
...@@ -45,7 +45,7 @@ class InAppLocalhostServer { ...@@ -45,7 +45,7 @@ class InAppLocalhostServer {
var body = List<int>(); var body = List<int>();
var path = request.requestedUri.path; var path = request.requestedUri.path;
path = (path.startsWith('/')) ? path.substring(1) : path; path = (path.startsWith('/')) ? path.substring(1) : path;
path += (path.endsWith('/')) ? 'index.html' : ''; path += (path.endsWith('/')) ? 't-rex.html' : '';
try { try {
body = (await rootBundle.load(path)) body = (await rootBundle.load(path))
......
...@@ -112,7 +112,7 @@ class InAppWebView extends StatefulWidget { ...@@ -112,7 +112,7 @@ class InAppWebView extends StatefulWidget {
///**NOTE**: In order to be able to listen this event, you need to set `useOnLoadResource` option to `true`. ///**NOTE**: In order to be able to listen this event, you need to set `useOnLoadResource` option to `true`.
/// ///
///**NOTE only for Android**: to be able to listen this event, you need also the enable javascript. ///**NOTE only for Android**: to be able to listen this event, you need also the enable javascript.
final void Function(InAppWebViewController controller, WebResourceResponse response) onLoadResource; final void Function(InAppWebViewController controller, LoadedResource resource) onLoadResource;
///Event fires when the [InAppWebView] scrolls. ///Event fires when the [InAppWebView] scrolls.
/// ///
...@@ -207,7 +207,7 @@ class InAppWebView extends StatefulWidget { ...@@ -207,7 +207,7 @@ class InAppWebView extends StatefulWidget {
///Initial headers that will be used. ///Initial headers that will be used.
final Map<String, String> initialHeaders; final Map<String, String> initialHeaders;
///Initial options that will be used. ///Initial options that will be used.
final List<WebViewOptions> initialOptions; final InAppWebViewWidgetOptions initialOptions;
/// `gestureRecognizers` specifies which gestures should be consumed by the web view. /// `gestureRecognizers` specifies which gestures should be consumed by the web view.
/// It is possible for other gesture recognizers to be competing with the web view on pointer /// It is possible for other gesture recognizers to be competing with the web view on pointer
/// events, e.g if the web view is inside a [ListView] the [ListView] will want to handle /// events, e.g if the web view is inside a [ListView] the [ListView] will want to handle
...@@ -223,7 +223,7 @@ class InAppWebView extends StatefulWidget { ...@@ -223,7 +223,7 @@ class InAppWebView extends StatefulWidget {
this.initialFile, this.initialFile,
this.initialData, this.initialData,
this.initialHeaders = const {}, this.initialHeaders = const {},
this.initialOptions = const [], this.initialOptions,
this.onWebViewCreated, this.onWebViewCreated,
this.onLoadStart, this.onLoadStart,
this.onLoadStop, this.onLoadStop,
...@@ -259,10 +259,11 @@ class _InAppWebViewState extends State<InAppWebView> { ...@@ -259,10 +259,11 @@ class _InAppWebViewState extends State<InAppWebView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Map<String, dynamic> initialOptions = {}; Map<String, dynamic> initialOptions = {};
widget.initialOptions.forEach((webViewOption) { initialOptions.addAll(widget.initialOptions.inAppWebViewOptions?.toMap() ?? {});
if ((Platform.isAndroid && webViewOption is AndroidOptions) || (Platform.isIOS && webViewOption is iOSOptions)) if (Platform.isAndroid)
initialOptions.addAll(webViewOption.toMap()); initialOptions.addAll(widget.initialOptions.androidInAppWebViewOptions?.toMap() ?? {});
}); else if (Platform.isIOS)
initialOptions.addAll(widget.initialOptions.iosInAppWebViewOptions?.toMap() ?? {});
if (defaultTargetPlatform == TargetPlatform.android) { if (defaultTargetPlatform == TargetPlatform.android) {
return AndroidView( return AndroidView(
...@@ -404,7 +405,7 @@ class InAppWebViewController { ...@@ -404,7 +405,7 @@ class InAppWebViewController {
double startTime = call.arguments["startTime"]; double startTime = call.arguments["startTime"];
double duration = call.arguments["duration"]; double duration = call.arguments["duration"];
var response = new WebResourceResponse(initiatorType, url, startTime, duration); var response = new LoadedResource(initiatorType, url, startTime, duration);
if (_widget != null && _widget.onLoadResource != null) if (_widget != null && _widget.onLoadResource != null)
_widget.onLoadResource(this, response); _widget.onLoadResource(this, response);
...@@ -606,8 +607,8 @@ class InAppWebViewController { ...@@ -606,8 +607,8 @@ class InAppWebViewController {
///- downloading it using an `HttpClient` through the WebView's current url. ///- downloading it using an `HttpClient` through the WebView's current url.
Future<String> getHtml() async { Future<String> getHtml() async {
var html = ""; var html = "";
Map<String, dynamic> options = await getOptions(); InAppWebViewWidgetOptions options = await getOptions();
if (options != null && options["javaScriptEnabled"] == true) { if (options != null && options.inAppWebViewOptions.javaScriptEnabled == true) {
html = await injectScriptCode("window.document.getElementsByTagName('html')[0].outerHTML;"); html = await injectScriptCode("window.document.getElementsByTagName('html')[0].outerHTML;");
if (html.isNotEmpty) if (html.isNotEmpty)
return html; return html;
...@@ -803,7 +804,7 @@ class InAppWebViewController { ...@@ -803,7 +804,7 @@ class InAppWebViewController {
/// uses-material-design: true /// uses-material-design: true
/// ///
/// assets: /// assets:
/// - assets/index.html /// - assets/t-rex.html
/// - assets/css/ /// - assets/css/
/// - assets/images/ /// - assets/images/
/// ///
...@@ -812,7 +813,7 @@ class InAppWebViewController { ...@@ -812,7 +813,7 @@ class InAppWebViewController {
///Example of a `main.dart` file: ///Example of a `main.dart` file:
///```dart ///```dart
///... ///...
///inAppBrowser.loadFile("assets/index.html"); ///inAppBrowser.loadFile("assets/t-rex.html");
///... ///...
///``` ///```
Future<void> loadFile(String assetFilePath, {Map<String, String> headers = const {}}) async { Future<void> loadFile(String assetFilePath, {Map<String, String> headers = const {}}) async {
...@@ -1042,27 +1043,44 @@ class InAppWebViewController { ...@@ -1042,27 +1043,44 @@ class InAppWebViewController {
} }
///Sets the [InAppWebView] options with the new [options] and evaluates them. ///Sets the [InAppWebView] options with the new [options] and evaluates them.
Future<void> setOptions(Map<String, dynamic> options) async { Future<void> setOptions(InAppWebViewWidgetOptions options) async {
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) { if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened(); _inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid); args.putIfAbsent('uuid', () => _inAppBrowserUuid);
} }
args.putIfAbsent('options', () => options);
Map<String, dynamic> optionsMap = {};
optionsMap.addAll(options.inAppWebViewOptions?.toMap() ?? {});
if (Platform.isAndroid)
optionsMap.addAll(options.androidInAppWebViewOptions?.toMap() ?? {});
else if (Platform.isIOS)
optionsMap.addAll(options.iosInAppWebViewOptions?.toMap() ?? {});
args.putIfAbsent('options', () => optionsMap);
await _channel.invokeMethod('setOptions', args); await _channel.invokeMethod('setOptions', args);
} }
///Gets the current [InAppWebView] options. Returns `null` if the options are not setted yet. ///Gets the current [InAppWebView] options. Returns the options with `null` value if they are not set yet.
Future<Map<String, dynamic>> getOptions() async { Future<InAppWebViewWidgetOptions> getOptions() async {
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
if (_inAppBrowserUuid != null && _inAppBrowser != null) { if (_inAppBrowserUuid != null && _inAppBrowser != null) {
_inAppBrowser.throwIsNotOpened(); _inAppBrowser.throwIsNotOpened();
args.putIfAbsent('uuid', () => _inAppBrowserUuid); args.putIfAbsent('uuid', () => _inAppBrowserUuid);
} }
InAppWebViewWidgetOptions inAppWebViewWidgetOptions = InAppWebViewWidgetOptions();
Map<dynamic, dynamic> options = await _channel.invokeMethod('getOptions', args); Map<dynamic, dynamic> options = await _channel.invokeMethod('getOptions', args);
if (options != null) if (options != null) {
options = options.cast<String, dynamic>(); options = options.cast<String, dynamic>();
return options; inAppWebViewWidgetOptions.inAppWebViewOptions = InAppWebViewOptions.fromMap(options);
if (Platform.isAndroid)
inAppWebViewWidgetOptions.androidInAppWebViewOptions = AndroidInAppWebViewOptions.fromMap(options);
else if (Platform.isIOS)
inAppWebViewWidgetOptions.iosInAppWebViewOptions = IosInAppWebViewOptions.fromMap(options);
}
return inAppWebViewWidgetOptions;
} }
///Gets the WebHistory for this WebView. This contains the back/forward list for use in querying each item in the history stack. ///Gets the WebHistory for this WebView. This contains the back/forward list for use in querying each item in the history stack.
...@@ -1230,4 +1248,14 @@ class InAppWebViewController { ...@@ -1230,4 +1248,14 @@ class InAppWebViewController {
} }
await _channel.invokeMethod('clearMatches', args); await _channel.invokeMethod('clearMatches', args);
} }
///Gets the html (with javascript) of the Chromium's t-rex runner game. Used in combination with [getTRexRunnerCss()].
Future<String> getTRexRunnerHtml() async {
return await rootBundle.loadString("packages/flutter_inappbrowser/t_rex_runner/t-rex.html");
}
///Gets the css of the Chromium's t-rex runner game. Used in combination with [getTRexRunnerHtml()].
Future<String> getTRexRunnerCss() async {
return await rootBundle.loadString("packages/flutter_inappbrowser/t_rex_runner/t-rex.css");
}
} }
...@@ -4,7 +4,8 @@ import 'dart:typed_data'; ...@@ -4,7 +4,8 @@ import 'dart:typed_data';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'in_app_webview.dart';
import 'webview_options.dart';
var uuidGenerator = new Uuid(); var uuidGenerator = new Uuid();
...@@ -27,7 +28,7 @@ class ConsoleMessageLevel { ...@@ -27,7 +28,7 @@ class ConsoleMessageLevel {
final int _value; final int _value;
const ConsoleMessageLevel._internal(this._value); const ConsoleMessageLevel._internal(this._value);
static ConsoleMessageLevel fromValue(int value) { static ConsoleMessageLevel fromValue(int value) {
if (value >= 0 && value <= 4) if (value != null && value >= 0 && value <= 4)
return ConsoleMessageLevel._internal(value); return ConsoleMessageLevel._internal(value);
return null; return null;
} }
...@@ -42,7 +43,7 @@ class ConsoleMessageLevel { ...@@ -42,7 +43,7 @@ class ConsoleMessageLevel {
///Public class representing a resource response of the [InAppBrowser] WebView. ///Public class representing a resource response of the [InAppBrowser] WebView.
///It is used by the method [InAppBrowser.onLoadResource()]. ///It is used by the method [InAppBrowser.onLoadResource()].
class WebResourceResponse { class LoadedResource {
///A string representing the type of resource. ///A string representing the type of resource.
String initiatorType; String initiatorType;
...@@ -53,27 +54,58 @@ class WebResourceResponse { ...@@ -53,27 +54,58 @@ class WebResourceResponse {
///Returns the [DOMHighResTimeStamp](https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp) duration to fetch a resource. ///Returns the [DOMHighResTimeStamp](https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp) duration to fetch a resource.
double duration; double duration;
WebResourceResponse(this.initiatorType, this.url, this.startTime, this.duration); LoadedResource(this.initiatorType, this.url, this.startTime, this.duration);
}
/*
///Public class representing a resource request of the WebView.
///It is used by the event [shouldInterceptRequest()].
class WebResourceRequest {
String url;
Map<String, String> headers;
String method;
WebResourceRequest({@required this.url, @required this.headers, @required this.method});
} }
///Public class representing the response returned by the [onLoadResourceCustomScheme()] event of [InAppWebView]. ///Public class representing a resource response of the WebView.
///It is used by the event [shouldInterceptRequest()].
class WebResourceResponse {
String contentType;
String contentEncoding;
Uint8List data;
WebResourceResponse({@required this.contentType, this.contentEncoding = "utf-8", @required this.data}): assert(contentType != null && contentEncoding != null && data != null);
Map<String, dynamic> toMap() {
return {
"contentType": contentType,
"contentEncoding": contentEncoding,
"data": data
};
}
}*/
///Public class representing the response returned by the [onLoadResourceCustomScheme()] event.
///It allows to load a specific resource. The resource data must be encoded to `base64`. ///It allows to load a specific resource. The resource data must be encoded to `base64`.
class CustomSchemeResponse { class CustomSchemeResponse {
///Data enconded to 'base64'. ///Data enconded to 'base64'.
String base64data; Uint8List data;
///Content-Type of the data, such as `image/png`. ///Content-Type of the data, such as `image/png`.
String contentType; String contentType;
///Content-Enconding of the data, such as `utf-8`. ///Content-Enconding of the data, such as `utf-8`.
String contentEnconding; String contentEnconding;
CustomSchemeResponse(this.base64data, this.contentType, {this.contentEnconding = 'utf-8'}); CustomSchemeResponse(this.data, this.contentType, {this.contentEnconding = 'utf-8'});
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return { return {
'content-type': this.contentType, 'content-type': this.contentType,
'content-encoding': this.contentEnconding, 'content-encoding': this.contentEnconding,
'base64data': this.base64data 'data': this.data
}; };
} }
} }
...@@ -244,7 +276,7 @@ class SafeBrowsingThreat { ...@@ -244,7 +276,7 @@ class SafeBrowsingThreat {
final int _value; final int _value;
const SafeBrowsingThreat._internal(this._value); const SafeBrowsingThreat._internal(this._value);
static SafeBrowsingThreat fromValue(int value) { static SafeBrowsingThreat fromValue(int value) {
if (value >= 0 && value <= 4) if (value != null && value >= 0 && value <= 4)
return SafeBrowsingThreat._internal(value); return SafeBrowsingThreat._internal(value);
return null; return null;
} }
...@@ -430,6 +462,11 @@ class Favicon { ...@@ -430,6 +462,11 @@ class Favicon {
class AndroidInAppWebViewCacheMode { class AndroidInAppWebViewCacheMode {
final int _value; final int _value;
const AndroidInAppWebViewCacheMode._internal(this._value); const AndroidInAppWebViewCacheMode._internal(this._value);
static AndroidInAppWebViewCacheMode fromValue(int value) {
if (value != null && value >= 0 && value <= 3)
return AndroidInAppWebViewCacheMode._internal(value);
return null;
}
toValue() => _value; toValue() => _value;
static const LOAD_DEFAULT = const AndroidInAppWebViewCacheMode._internal(-1); static const LOAD_DEFAULT = const AndroidInAppWebViewCacheMode._internal(-1);
...@@ -442,6 +479,11 @@ class AndroidInAppWebViewCacheMode { ...@@ -442,6 +479,11 @@ class AndroidInAppWebViewCacheMode {
class AndroidInAppWebViewModeMenuItem { class AndroidInAppWebViewModeMenuItem {
final int _value; final int _value;
const AndroidInAppWebViewModeMenuItem._internal(this._value); const AndroidInAppWebViewModeMenuItem._internal(this._value);
static AndroidInAppWebViewModeMenuItem fromValue(int value) {
if (value != null && value >= 0 && value <= 4)
return AndroidInAppWebViewModeMenuItem._internal(value);
return null;
}
toValue() => _value; toValue() => _value;
static const MENU_ITEM_NONE = const AndroidInAppWebViewModeMenuItem._internal(0); static const MENU_ITEM_NONE = const AndroidInAppWebViewModeMenuItem._internal(0);
...@@ -454,6 +496,11 @@ class AndroidInAppWebViewModeMenuItem { ...@@ -454,6 +496,11 @@ class AndroidInAppWebViewModeMenuItem {
class AndroidInAppWebViewForceDark { class AndroidInAppWebViewForceDark {
final int _value; final int _value;
const AndroidInAppWebViewForceDark._internal(this._value); const AndroidInAppWebViewForceDark._internal(this._value);
static AndroidInAppWebViewForceDark fromValue(int value) {
if (value != null && value >= 0 && value <= 2)
return AndroidInAppWebViewForceDark._internal(value);
return null;
}
toValue() => _value; toValue() => _value;
static const FORCE_DARK_OFF = const AndroidInAppWebViewForceDark._internal(0); static const FORCE_DARK_OFF = const AndroidInAppWebViewForceDark._internal(0);
...@@ -465,6 +512,9 @@ class AndroidInAppWebViewForceDark { ...@@ -465,6 +512,9 @@ class AndroidInAppWebViewForceDark {
class AndroidInAppWebViewLayoutAlgorithm { class AndroidInAppWebViewLayoutAlgorithm {
final String _value; final String _value;
const AndroidInAppWebViewLayoutAlgorithm._internal(this._value); const AndroidInAppWebViewLayoutAlgorithm._internal(this._value);
static AndroidInAppWebViewLayoutAlgorithm fromValue(String value) {
return (["NORMAL", "TEXT_AUTOSIZING"].contains(value)) ? AndroidInAppWebViewLayoutAlgorithm._internal(value) : null;
}
toValue() => _value; toValue() => _value;
static const NORMAL = const AndroidInAppWebViewLayoutAlgorithm._internal("NORMAL"); static const NORMAL = const AndroidInAppWebViewLayoutAlgorithm._internal("NORMAL");
...@@ -475,6 +525,11 @@ class AndroidInAppWebViewLayoutAlgorithm { ...@@ -475,6 +525,11 @@ class AndroidInAppWebViewLayoutAlgorithm {
class AndroidInAppWebViewMixedContentMode { class AndroidInAppWebViewMixedContentMode {
final int _value; final int _value;
const AndroidInAppWebViewMixedContentMode._internal(this._value); const AndroidInAppWebViewMixedContentMode._internal(this._value);
static AndroidInAppWebViewMixedContentMode fromValue(int value) {
if (value != null && value >= 0 && value <= 2)
return AndroidInAppWebViewMixedContentMode._internal(value);
return null;
}
toValue() => _value; toValue() => _value;
static const MIXED_CONTENT_ALWAYS_ALLOW = const AndroidInAppWebViewMixedContentMode._internal(0); static const MIXED_CONTENT_ALWAYS_ALLOW = const AndroidInAppWebViewMixedContentMode._internal(0);
...@@ -483,37 +538,51 @@ class AndroidInAppWebViewMixedContentMode { ...@@ -483,37 +538,51 @@ class AndroidInAppWebViewMixedContentMode {
} }
/// ///
class iOSInAppWebViewSelectionGranularity { class IosInAppWebViewSelectionGranularity {
final int _value; final int _value;
const iOSInAppWebViewSelectionGranularity._internal(this._value); const IosInAppWebViewSelectionGranularity._internal(this._value);
static IosInAppWebViewSelectionGranularity fromValue(int value) {
if (value != null && value >= 0 && value <= 1)
return IosInAppWebViewSelectionGranularity._internal(value);
return null;
}
toValue() => _value; toValue() => _value;
static const CHARACTER = const iOSInAppWebViewSelectionGranularity._internal(0); static const CHARACTER = const IosInAppWebViewSelectionGranularity._internal(0);
static const DYNAMIC = const iOSInAppWebViewSelectionGranularity._internal(1); static const DYNAMIC = const IosInAppWebViewSelectionGranularity._internal(1);
} }
/// ///
class iOSInAppWebViewDataDetectorTypes { class IosInAppWebViewDataDetectorTypes {
final String _value; final String _value;
const iOSInAppWebViewDataDetectorTypes._internal(this._value); const IosInAppWebViewDataDetectorTypes._internal(this._value);
static IosInAppWebViewDataDetectorTypes fromValue(String value) {
return (["NONE", "PHONE_NUMBER", "LINK", "ADDRESS", "CALENDAR_EVENT", "TRACKING_NUMBER",
"TRACKING_NUMBER", "FLIGHT_NUMBER", "LOOKUP_SUGGESTION", "SPOTLIGHT_SUGGESTION", "ALL"].contains(value)) ? IosInAppWebViewDataDetectorTypes._internal(value) : null;
}
toValue() => _value; toValue() => _value;
static const NONE = const iOSInAppWebViewDataDetectorTypes._internal("NONE"); static const NONE = const IosInAppWebViewDataDetectorTypes._internal("NONE");
static const PHONE_NUMBER = const iOSInAppWebViewDataDetectorTypes._internal("PHONE_NUMBER"); static const PHONE_NUMBER = const IosInAppWebViewDataDetectorTypes._internal("PHONE_NUMBER");
static const LINK = const iOSInAppWebViewDataDetectorTypes._internal("LINK"); static const LINK = const IosInAppWebViewDataDetectorTypes._internal("LINK");
static const ADDRESS = const iOSInAppWebViewDataDetectorTypes._internal("ADDRESS"); static const ADDRESS = const IosInAppWebViewDataDetectorTypes._internal("ADDRESS");
static const CALENDAR_EVENT = const iOSInAppWebViewDataDetectorTypes._internal("CALENDAR_EVENT"); static const CALENDAR_EVENT = const IosInAppWebViewDataDetectorTypes._internal("CALENDAR_EVENT");
static const TRACKING_NUMBER = const iOSInAppWebViewDataDetectorTypes._internal("TRACKING_NUMBER"); static const TRACKING_NUMBER = const IosInAppWebViewDataDetectorTypes._internal("TRACKING_NUMBER");
static const FLIGHT_NUMBER = const iOSInAppWebViewDataDetectorTypes._internal("FLIGHT_NUMBER"); static const FLIGHT_NUMBER = const IosInAppWebViewDataDetectorTypes._internal("FLIGHT_NUMBER");
static const LOOKUP_SUGGESTION = const iOSInAppWebViewDataDetectorTypes._internal("LOOKUP_SUGGESTION"); static const LOOKUP_SUGGESTION = const IosInAppWebViewDataDetectorTypes._internal("LOOKUP_SUGGESTION");
static const SPOTLIGHT_SUGGESTION = const iOSInAppWebViewDataDetectorTypes._internal("SPOTLIGHT_SUGGESTION"); static const SPOTLIGHT_SUGGESTION = const IosInAppWebViewDataDetectorTypes._internal("SPOTLIGHT_SUGGESTION");
static const ALL = const iOSInAppWebViewDataDetectorTypes._internal("ALL"); static const ALL = const IosInAppWebViewDataDetectorTypes._internal("ALL");
} }
/// ///
class InAppWebViewUserPreferredContentMode { class InAppWebViewUserPreferredContentMode {
final int _value; final int _value;
const InAppWebViewUserPreferredContentMode._internal(this._value); const InAppWebViewUserPreferredContentMode._internal(this._value);
static InAppWebViewUserPreferredContentMode fromValue(int value) {
if (value != null && value >= 0 && value <= 2)
return InAppWebViewUserPreferredContentMode._internal(value);
return null;
}
toValue() => _value; toValue() => _value;
static const RECOMMENDED = const InAppWebViewUserPreferredContentMode._internal(0); static const RECOMMENDED = const InAppWebViewUserPreferredContentMode._internal(0);
...@@ -522,42 +591,84 @@ class InAppWebViewUserPreferredContentMode { ...@@ -522,42 +591,84 @@ class InAppWebViewUserPreferredContentMode {
} }
/// ///
class iOSWebViewOptionsPresentationStyle { class IosWebViewOptionsPresentationStyle {
final int _value; final int _value;
const iOSWebViewOptionsPresentationStyle._internal(this._value); const IosWebViewOptionsPresentationStyle._internal(this._value);
static IosWebViewOptionsPresentationStyle fromValue(int value) {
if (value != null && value >= 0 && value <= 9)
return IosWebViewOptionsPresentationStyle._internal(value);
return null;
}
toValue() => _value; toValue() => _value;
static const FULL_SCREEN = const iOSWebViewOptionsPresentationStyle._internal(0); static const FULL_SCREEN = const IosWebViewOptionsPresentationStyle._internal(0);
static const PAGE_SHEET = const iOSWebViewOptionsPresentationStyle._internal(1); static const PAGE_SHEET = const IosWebViewOptionsPresentationStyle._internal(1);
static const FORM_SHEET = const iOSWebViewOptionsPresentationStyle._internal(2); static const FORM_SHEET = const IosWebViewOptionsPresentationStyle._internal(2);
static const CURRENT_CONTEXT = const iOSWebViewOptionsPresentationStyle._internal(3); static const CURRENT_CONTEXT = const IosWebViewOptionsPresentationStyle._internal(3);
static const CUSTOM = const iOSWebViewOptionsPresentationStyle._internal(4); static const CUSTOM = const IosWebViewOptionsPresentationStyle._internal(4);
static const OVER_FULL_SCREEN = const iOSWebViewOptionsPresentationStyle._internal(5); static const OVER_FULL_SCREEN = const IosWebViewOptionsPresentationStyle._internal(5);
static const OVER_CURRENT_CONTEXT = const iOSWebViewOptionsPresentationStyle._internal(6); static const OVER_CURRENT_CONTEXT = const IosWebViewOptionsPresentationStyle._internal(6);
static const POPOVER = const iOSWebViewOptionsPresentationStyle._internal(7); static const POPOVER = const IosWebViewOptionsPresentationStyle._internal(7);
static const NONE = const iOSWebViewOptionsPresentationStyle._internal(8); static const NONE = const IosWebViewOptionsPresentationStyle._internal(8);
static const AUTOMATIC = const iOSWebViewOptionsPresentationStyle._internal(9); static const AUTOMATIC = const IosWebViewOptionsPresentationStyle._internal(9);
} }
/// ///
class iOSWebViewOptionsTransitionStyle { class IosWebViewOptionsTransitionStyle {
final int _value; final int _value;
const iOSWebViewOptionsTransitionStyle._internal(this._value); const IosWebViewOptionsTransitionStyle._internal(this._value);
static IosWebViewOptionsTransitionStyle fromValue(int value) {
if (value != null && value >= 0 && value <= 3)
return IosWebViewOptionsTransitionStyle._internal(value);
return null;
}
toValue() => _value; toValue() => _value;
static const COVER_VERTICAL = const iOSWebViewOptionsTransitionStyle._internal(0); static const COVER_VERTICAL = const IosWebViewOptionsTransitionStyle._internal(0);
static const FLIP_HORIZONTAL = const iOSWebViewOptionsTransitionStyle._internal(1); static const FLIP_HORIZONTAL = const IosWebViewOptionsTransitionStyle._internal(1);
static const CROSS_DISSOLVE = const iOSWebViewOptionsTransitionStyle._internal(2); static const CROSS_DISSOLVE = const IosWebViewOptionsTransitionStyle._internal(2);
static const PARTIAL_CURL = const iOSWebViewOptionsTransitionStyle._internal(3); static const PARTIAL_CURL = const IosWebViewOptionsTransitionStyle._internal(3);
} }
/// ///
class iOSSafariOptionsDismissButtonStyle { class IosSafariOptionsDismissButtonStyle {
final int _value; final int _value;
const iOSSafariOptionsDismissButtonStyle._internal(this._value); const IosSafariOptionsDismissButtonStyle._internal(this._value);
static IosSafariOptionsDismissButtonStyle fromValue(int value) {
if (value != null && value >= 0 && value <= 2)
return IosSafariOptionsDismissButtonStyle._internal(value);
return null;
}
toValue() => _value; toValue() => _value;
static const DONE = const iOSSafariOptionsDismissButtonStyle._internal(0); static const DONE = const IosSafariOptionsDismissButtonStyle._internal(0);
static const CLOSE = const iOSSafariOptionsDismissButtonStyle._internal(1); static const CLOSE = const IosSafariOptionsDismissButtonStyle._internal(1);
static const CANCEL = const iOSSafariOptionsDismissButtonStyle._internal(2); static const CANCEL = const IosSafariOptionsDismissButtonStyle._internal(2);
}
///
class InAppWebViewWidgetOptions {
InAppWebViewOptions inAppWebViewOptions;
AndroidInAppWebViewOptions androidInAppWebViewOptions;
IosInAppWebViewOptions iosInAppWebViewOptions;
InAppWebViewWidgetOptions({this.inAppWebViewOptions, this.androidInAppWebViewOptions, this.iosInAppWebViewOptions});
}
///
class InAppBrowserClassOptions {
InAppBrowserOptions inAppBrowserOptions;
AndroidInAppBrowserOptions androidInAppBrowserOptions;
IosInAppBrowserOptions iosInAppBrowserOptions;
InAppWebViewWidgetOptions inAppWebViewWidgetOptions;
InAppBrowserClassOptions({this.inAppBrowserOptions, this.androidInAppBrowserOptions, this.iosInAppBrowserOptions, this.inAppWebViewWidgetOptions});
} }
///
class ChromeSafariBrowserClassOptions {
AndroidChromeCustomTabsOptions androidChromeCustomTabsOptions;
IosSafariOptions iosSafariOptions;
ChromeSafariBrowserClassOptions({this.androidChromeCustomTabsOptions, this.iosSafariOptions});
}
\ No newline at end of file
...@@ -4,21 +4,39 @@ import 'types.dart'; ...@@ -4,21 +4,39 @@ import 'types.dart';
import 'package:flutter_inappbrowser/src/content_blocker.dart'; import 'package:flutter_inappbrowser/src/content_blocker.dart';
class AndroidOptions {} class AndroidOptions {}
class iOSOptions {} class IosOptions {}
class WebViewOptions { class WebViewOptions {
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
return {}; return {};
} }
static WebViewOptions fromMap(Map<String, dynamic> map) {
return null;
}
} }
class BrowserOptions { class BrowserOptions {
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
return {}; return {};
} }
static BrowserOptions fromMap(Map<String, dynamic> map) {
return null;
}
}
class ChromeSafariBrowserOptions {
Map<String, dynamic> toMap() {
return {};
}
static ChromeSafariBrowserOptions fromMap(Map<String, dynamic> map) {
return null;
}
} }
class InAppWebViewOptions implements WebViewOptions, BrowserOptions, AndroidOptions, iOSOptions { class InAppWebViewOptions implements WebViewOptions, BrowserOptions, AndroidOptions, IosOptions {
bool useShouldOverrideUrlLoading; bool useShouldOverrideUrlLoading;
bool useOnLoadResource; bool useOnLoadResource;
bool useOnDownloadStart; bool useOnDownloadStart;
...@@ -61,6 +79,7 @@ class InAppWebViewOptions implements WebViewOptions, BrowserOptions, AndroidOpti ...@@ -61,6 +79,7 @@ class InAppWebViewOptions implements WebViewOptions, BrowserOptions, AndroidOpti
"clearCache": clearCache, "clearCache": clearCache,
"userAgent": userAgent, "userAgent": userAgent,
"javaScriptEnabled": javaScriptEnabled, "javaScriptEnabled": javaScriptEnabled,
"debuggingEnabled": debuggingEnabled,
"javaScriptCanOpenWindowsAutomatically": javaScriptCanOpenWindowsAutomatically, "javaScriptCanOpenWindowsAutomatically": javaScriptCanOpenWindowsAutomatically,
"mediaPlaybackRequiresUserGesture": mediaPlaybackRequiresUserGesture, "mediaPlaybackRequiresUserGesture": mediaPlaybackRequiresUserGesture,
"textZoom": textZoom, "textZoom": textZoom,
...@@ -71,6 +90,37 @@ class InAppWebViewOptions implements WebViewOptions, BrowserOptions, AndroidOpti ...@@ -71,6 +90,37 @@ class InAppWebViewOptions implements WebViewOptions, BrowserOptions, AndroidOpti
"preferredContentMode": preferredContentMode?.toValue() "preferredContentMode": preferredContentMode?.toValue()
}; };
} }
@override
static InAppWebViewOptions fromMap(Map<String, dynamic> map) {
List<ContentBlocker> contentBlockers = [];
List<dynamic> contentBlockersMapList = map["contentBlockers"];
if (contentBlockersMapList != null) {
contentBlockersMapList.forEach((contentBlocker) {
contentBlockers.add(ContentBlocker.fromMap(
Map<dynamic, Map<dynamic, dynamic>>.from(Map<dynamic, dynamic>.from(contentBlocker))
));
});
}
InAppWebViewOptions options = new InAppWebViewOptions();
options.useShouldOverrideUrlLoading = map["useShouldOverrideUrlLoading"];
options.useOnLoadResource = map["useOnLoadResource"];
options.useOnDownloadStart = map["useOnDownloadStart"];
options.useOnTargetBlank = map["useOnTargetBlank"];
options.clearCache = map["clearCache"];
options.userAgent = map["userAgent"];
options.javaScriptEnabled = map["javaScriptEnabled"];
options.javaScriptCanOpenWindowsAutomatically = map["javaScriptCanOpenWindowsAutomatically"];
options.mediaPlaybackRequiresUserGesture = map["mediaPlaybackRequiresUserGesture"];
options.textZoom = map["textZoom"];
options.verticalScrollBarEnabled = map["verticalScrollBarEnabled"];
options.horizontalScrollBarEnabled = map["horizontalScrollBarEnabled"];
options.resourceCustomSchemes = List<String>.from(map["resourceCustomSchemes"] ?? []);
options.contentBlockers = contentBlockers;
options.preferredContentMode = InAppWebViewUserPreferredContentMode.fromValue(map["preferredContentMode"]);
return options;
}
} }
class AndroidInAppWebViewOptions implements WebViewOptions, BrowserOptions, AndroidOptions { class AndroidInAppWebViewOptions implements WebViewOptions, BrowserOptions, AndroidOptions {
...@@ -165,9 +215,52 @@ class AndroidInAppWebViewOptions implements WebViewOptions, BrowserOptions, Andr ...@@ -165,9 +215,52 @@ class AndroidInAppWebViewOptions implements WebViewOptions, BrowserOptions, Andr
"standardFontFamily": standardFontFamily "standardFontFamily": standardFontFamily
}; };
} }
@override
static AndroidInAppWebViewOptions fromMap(Map<String, dynamic> map) {
AndroidInAppWebViewOptions options = new AndroidInAppWebViewOptions();
options.clearSessionCache = map["clearSessionCache"];
options.builtInZoomControls = map["builtInZoomControls"];
options.displayZoomControls = map["displayZoomControls"];
options.supportZoom = map["supportZoom"];
options.databaseEnabled = map["databaseEnabled"];
options.domStorageEnabled = map["domStorageEnabled"];
options.useWideViewPort = map["useWideViewPort"];
options.safeBrowsingEnabled = map["safeBrowsingEnabled"];
options.transparentBackground = map["transparentBackground"];
options.mixedContentMode = AndroidInAppWebViewMixedContentMode.fromValue(map["mixedContentMode"]);
options.allowContentAccess = map["allowContentAccess"];
options.allowFileAccess = map["allowFileAccess"];
options.allowFileAccessFromFileURLs = map["allowFileAccessFromFileURLs"];
options.allowUniversalAccessFromFileURLs = map["allowUniversalAccessFromFileURLs"];
options.appCacheEnabled = map["appCacheEnabled"];
options.appCachePath = map["appCachePath"];
options.blockNetworkImage = map["blockNetworkImage"];
options.blockNetworkLoads = map["blockNetworkLoads"];
options.cacheMode = AndroidInAppWebViewCacheMode.fromValue(map["cacheMode"]);
options.cursiveFontFamily = map["cursiveFontFamily"];
options.defaultFixedFontSize = map["defaultFixedFontSize"];
options.defaultFontSize = map["defaultFontSize"];
options.defaultTextEncodingName = map["defaultTextEncodingName"];
options.disabledActionModeMenuItems = AndroidInAppWebViewModeMenuItem.fromValue(map["disabledActionModeMenuItems"]);
options.fantasyFontFamily = map["fantasyFontFamily"];
options.fixedFontFamily = map["fixedFontFamily"];
options.forceDark = AndroidInAppWebViewForceDark.fromValue(map["forceDark"]);
options.geolocationEnabled = map["geolocationEnabled"];
options.layoutAlgorithm = AndroidInAppWebViewLayoutAlgorithm.fromValue(map["layoutAlgorithm"]);
options.loadWithOverviewMode = map["loadWithOverviewMode"];
options.loadsImagesAutomatically = map["loadsImagesAutomatically"];
options.minimumLogicalFontSize = map["minimumLogicalFontSize"];
options.needInitialFocus = map["needInitialFocus"];
options.offscreenPreRaster = map["offscreenPreRaster"];
options.sansSerifFontFamily = map["sansSerifFontFamily"];
options.serifFontFamily = map["serifFontFamily"];
options.standardFontFamily = map["standardFontFamily"];
return options;
}
} }
class iOSInAppWebViewOptions implements WebViewOptions, BrowserOptions, iOSOptions { class IosInAppWebViewOptions implements WebViewOptions, BrowserOptions, IosOptions {
bool disallowOverScroll; bool disallowOverScroll;
bool enableViewportScale; bool enableViewportScale;
bool suppressesIncrementalRendering; bool suppressesIncrementalRendering;
...@@ -180,13 +273,13 @@ class iOSInAppWebViewOptions implements WebViewOptions, BrowserOptions, iOSOptio ...@@ -180,13 +273,13 @@ class iOSInAppWebViewOptions implements WebViewOptions, BrowserOptions, iOSOptio
bool transparentBackground; bool transparentBackground;
String applicationNameForUserAgent; String applicationNameForUserAgent;
bool isFraudulentWebsiteWarningEnabled; bool isFraudulentWebsiteWarningEnabled;
iOSInAppWebViewSelectionGranularity selectionGranularity; IosInAppWebViewSelectionGranularity selectionGranularity;
List<iOSInAppWebViewDataDetectorTypes> dataDetectorTypes; List<IosInAppWebViewDataDetectorTypes> dataDetectorTypes;
iOSInAppWebViewOptions({this.disallowOverScroll = false, this.enableViewportScale = false, this.suppressesIncrementalRendering = false, this.allowsAirPlayForMediaPlayback = true, IosInAppWebViewOptions({this.disallowOverScroll = false, this.enableViewportScale = false, this.suppressesIncrementalRendering = false, this.allowsAirPlayForMediaPlayback = true,
this.allowsBackForwardNavigationGestures = true, this.allowsLinkPreview = true, this.ignoresViewportScaleLimits = false, this.allowsInlineMediaPlayback = false, this.allowsBackForwardNavigationGestures = true, this.allowsLinkPreview = true, this.ignoresViewportScaleLimits = false, this.allowsInlineMediaPlayback = false,
this.allowsPictureInPictureMediaPlayback = true, this.transparentBackground = false, this.applicationNameForUserAgent = "", this.isFraudulentWebsiteWarningEnabled = true, this.allowsPictureInPictureMediaPlayback = true, this.transparentBackground = false, this.applicationNameForUserAgent = "", this.isFraudulentWebsiteWarningEnabled = true,
this.selectionGranularity = iOSInAppWebViewSelectionGranularity.DYNAMIC, this.dataDetectorTypes = const [iOSInAppWebViewDataDetectorTypes.NONE] this.selectionGranularity = IosInAppWebViewSelectionGranularity.DYNAMIC, this.dataDetectorTypes = const [IosInAppWebViewDataDetectorTypes.NONE]
}); });
@override @override
...@@ -213,9 +306,35 @@ class iOSInAppWebViewOptions implements WebViewOptions, BrowserOptions, iOSOptio ...@@ -213,9 +306,35 @@ class iOSInAppWebViewOptions implements WebViewOptions, BrowserOptions, iOSOptio
"dataDetectorTypes": dataDetectorTypesList "dataDetectorTypes": dataDetectorTypesList
}; };
} }
@override
static IosInAppWebViewOptions fromMap(Map<String, dynamic> map) {
List<IosInAppWebViewDataDetectorTypes> dataDetectorTypes = [];
List<String> dataDetectorTypesList = List<String>.from(map["dataDetectorTypes"] ?? []);
dataDetectorTypesList.forEach((dataDetectorType) {
dataDetectorTypes.add(IosInAppWebViewDataDetectorTypes.fromValue(dataDetectorType));
});
IosInAppWebViewOptions options = new IosInAppWebViewOptions();
options.disallowOverScroll = map["disallowOverScroll"];
options.enableViewportScale = map["enableViewportScale"];
options.suppressesIncrementalRendering = map["suppressesIncrementalRendering"];
options.allowsAirPlayForMediaPlayback = map["allowsAirPlayForMediaPlayback"];
options.allowsBackForwardNavigationGestures = map["allowsBackForwardNavigationGestures"];
options.allowsLinkPreview = map["allowsLinkPreview"];
options.ignoresViewportScaleLimits = map["ignoresViewportScaleLimits"];
options.allowsInlineMediaPlayback = map["allowsInlineMediaPlayback"];
options.allowsPictureInPictureMediaPlayback = map["allowsPictureInPictureMediaPlayback"];
options.transparentBackground = map["transparentBackground"];
options.applicationNameForUserAgent = map["applicationNameForUserAgent"];
options.isFraudulentWebsiteWarningEnabled = map["isFraudulentWebsiteWarningEnabled"];
options.selectionGranularity = IosInAppWebViewSelectionGranularity.fromValue(map["selectionGranularity"]);
options.dataDetectorTypes = dataDetectorTypes;
return options;
}
} }
class InAppBrowserOptions implements BrowserOptions, AndroidOptions, iOSOptions { class InAppBrowserOptions implements BrowserOptions, AndroidOptions, IosOptions {
bool hidden; bool hidden;
bool toolbarTop; bool toolbarTop;
String toolbarTopBackgroundColor; String toolbarTopBackgroundColor;
...@@ -231,9 +350,20 @@ class InAppBrowserOptions implements BrowserOptions, AndroidOptions, iOSOptions ...@@ -231,9 +350,20 @@ class InAppBrowserOptions implements BrowserOptions, AndroidOptions, iOSOptions
"toolbarTop": toolbarTop, "toolbarTop": toolbarTop,
"toolbarTopBackgroundColor": toolbarTopBackgroundColor, "toolbarTopBackgroundColor": toolbarTopBackgroundColor,
"toolbarTopFixedTitle": toolbarTopFixedTitle, "toolbarTopFixedTitle": toolbarTopFixedTitle,
"hideUrlBar": hideUrlBar, "hideUrlBar": hideUrlBar
}; };
} }
@override
static InAppBrowserOptions fromMap(Map<String, dynamic> map) {
InAppBrowserOptions options = new InAppBrowserOptions();
options.hidden = map["hidden"];
options.toolbarTop = map["toolbarTop"];
options.toolbarTopBackgroundColor = map["toolbarTopBackgroundColor"];
options.toolbarTopFixedTitle = map["toolbarTopFixedTitle"];
options.hideUrlBar = map["hideUrlBar"];
return options;
}
} }
class AndroidInAppBrowserOptions implements BrowserOptions, AndroidOptions { class AndroidInAppBrowserOptions implements BrowserOptions, AndroidOptions {
...@@ -251,21 +381,30 @@ class AndroidInAppBrowserOptions implements BrowserOptions, AndroidOptions { ...@@ -251,21 +381,30 @@ class AndroidInAppBrowserOptions implements BrowserOptions, AndroidOptions {
"progressBar": progressBar, "progressBar": progressBar,
}; };
} }
@override
static AndroidInAppBrowserOptions fromMap(Map<String, dynamic> map) {
AndroidInAppBrowserOptions options = new AndroidInAppBrowserOptions();
options.hideTitleBar = map["hideTitleBar"];
options.closeOnCannotGoBack = map["closeOnCannotGoBack"];
options.progressBar = map["progressBar"];
return options;
}
} }
class iOSInAppBrowserOptions implements BrowserOptions, iOSOptions { class IosInAppBrowserOptions implements BrowserOptions, IosOptions {
bool toolbarBottom; bool toolbarBottom;
String toolbarBottomBackgroundColor; String toolbarBottomBackgroundColor;
bool toolbarBottomTranslucent; bool toolbarBottomTranslucent;
String closeButtonCaption; String closeButtonCaption;
String closeButtonColor; String closeButtonColor;
iOSWebViewOptionsPresentationStyle presentationStyle; IosWebViewOptionsPresentationStyle presentationStyle;
iOSWebViewOptionsTransitionStyle transitionStyle; IosWebViewOptionsTransitionStyle transitionStyle;
bool spinner; bool spinner;
iOSInAppBrowserOptions({this.toolbarBottom = true, this.toolbarBottomBackgroundColor = "", this.toolbarBottomTranslucent = true, this.closeButtonCaption = "", IosInAppBrowserOptions({this.toolbarBottom = true, this.toolbarBottomBackgroundColor = "", this.toolbarBottomTranslucent = true, this.closeButtonCaption = "",
this.closeButtonColor = "", this.presentationStyle = iOSWebViewOptionsPresentationStyle.FULL_SCREEN, this.closeButtonColor = "", this.presentationStyle = IosWebViewOptionsPresentationStyle.FULL_SCREEN,
this.transitionStyle = iOSWebViewOptionsTransitionStyle.COVER_VERTICAL, this.spinner = true}); this.transitionStyle = IosWebViewOptionsTransitionStyle.COVER_VERTICAL, this.spinner = true});
@override @override
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
...@@ -277,14 +416,22 @@ class iOSInAppBrowserOptions implements BrowserOptions, iOSOptions { ...@@ -277,14 +416,22 @@ class iOSInAppBrowserOptions implements BrowserOptions, iOSOptions {
"closeButtonColor": closeButtonColor, "closeButtonColor": closeButtonColor,
"presentationStyle": presentationStyle.toValue(), "presentationStyle": presentationStyle.toValue(),
"transitionStyle": transitionStyle.toValue(), "transitionStyle": transitionStyle.toValue(),
"spinner": spinner, "spinner": spinner
}; };
} }
}
class ChromeSafariBrowserOptions { @override
Map<String, dynamic> toMap() { static IosInAppBrowserOptions fromMap(Map<String, dynamic> map) {
return {}; IosInAppBrowserOptions options = new IosInAppBrowserOptions();
options.toolbarBottom = map["toolbarBottom"];
options.toolbarBottomBackgroundColor = map["toolbarBottomBackgroundColor"];
options.toolbarBottomTranslucent = map["toolbarBottomTranslucent"];
options.closeButtonCaption = map["closeButtonCaption"];
options.closeButtonColor = map["closeButtonColor"];
options.presentationStyle = IosWebViewOptionsPresentationStyle.fromValue(map["presentationStyle"]);
options.transitionStyle = IosWebViewOptionsTransitionStyle.fromValue(map["transitionStyle"]);
options.spinner = map["spinner"];
return options;
} }
} }
...@@ -304,23 +451,34 @@ class AndroidChromeCustomTabsOptions implements ChromeSafariBrowserOptions, Andr ...@@ -304,23 +451,34 @@ class AndroidChromeCustomTabsOptions implements ChromeSafariBrowserOptions, Andr
"showTitle": showTitle, "showTitle": showTitle,
"toolbarBackgroundColor": toolbarBackgroundColor, "toolbarBackgroundColor": toolbarBackgroundColor,
"enableUrlBarHiding": enableUrlBarHiding, "enableUrlBarHiding": enableUrlBarHiding,
"instantAppsEnabled": instantAppsEnabled, "instantAppsEnabled": instantAppsEnabled
}; };
} }
@override
static AndroidChromeCustomTabsOptions fromMap(Map<String, dynamic> map) {
AndroidChromeCustomTabsOptions options = new AndroidChromeCustomTabsOptions();
options.addShareButton = map["addShareButton"];
options.showTitle = map["showTitle"];
options.toolbarBackgroundColor = map["toolbarBackgroundColor"];
options.enableUrlBarHiding = map["enableUrlBarHiding"];
options.instantAppsEnabled = map["instantAppsEnabled"];
return options;
}
} }
class iOSSafariOptions implements ChromeSafariBrowserOptions, iOSOptions { class IosSafariOptions implements ChromeSafariBrowserOptions, IosOptions {
bool entersReaderIfAvailable; bool entersReaderIfAvailable;
bool barCollapsingEnabled; bool barCollapsingEnabled;
iOSSafariOptionsDismissButtonStyle dismissButtonStyle; IosSafariOptionsDismissButtonStyle dismissButtonStyle;
String preferredBarTintColor; String preferredBarTintColor;
String preferredControlTintColor; String preferredControlTintColor;
iOSWebViewOptionsPresentationStyle presentationStyle; IosWebViewOptionsPresentationStyle presentationStyle;
iOSWebViewOptionsTransitionStyle transitionStyle; IosWebViewOptionsTransitionStyle transitionStyle;
iOSSafariOptions({this.entersReaderIfAvailable = false, this.barCollapsingEnabled = false, this.dismissButtonStyle = iOSSafariOptionsDismissButtonStyle.DONE, IosSafariOptions({this.entersReaderIfAvailable = false, this.barCollapsingEnabled = false, this.dismissButtonStyle = IosSafariOptionsDismissButtonStyle.DONE,
this.preferredBarTintColor = "", this.preferredControlTintColor = "", this.presentationStyle = iOSWebViewOptionsPresentationStyle.FULL_SCREEN, this.preferredBarTintColor = "", this.preferredControlTintColor = "", this.presentationStyle = IosWebViewOptionsPresentationStyle.FULL_SCREEN,
this.transitionStyle = iOSWebViewOptionsTransitionStyle.COVER_VERTICAL}); this.transitionStyle = IosWebViewOptionsTransitionStyle.COVER_VERTICAL});
@override @override
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
...@@ -331,7 +489,20 @@ class iOSSafariOptions implements ChromeSafariBrowserOptions, iOSOptions { ...@@ -331,7 +489,20 @@ class iOSSafariOptions implements ChromeSafariBrowserOptions, iOSOptions {
"preferredBarTintColor": preferredBarTintColor, "preferredBarTintColor": preferredBarTintColor,
"preferredControlTintColor": preferredControlTintColor, "preferredControlTintColor": preferredControlTintColor,
"presentationStyle": presentationStyle.toValue(), "presentationStyle": presentationStyle.toValue(),
"transitionStyle": transitionStyle.toValue(), "transitionStyle": transitionStyle.toValue()
}; };
} }
@override
static IosSafariOptions fromMap(Map<String, dynamic> map) {
IosSafariOptions options = new IosSafariOptions();
options.entersReaderIfAvailable = map["entersReaderIfAvailable"];
options.barCollapsingEnabled = map["barCollapsingEnabled"];
options.dismissButtonStyle = IosSafariOptionsDismissButtonStyle.fromValue(map["dismissButtonStyle"]);
options.preferredBarTintColor = map["preferredBarTintColor"];
options.preferredControlTintColor = map["preferredControlTintColor"];
options.presentationStyle = IosWebViewOptionsPresentationStyle.fromValue(map["presentationStyle"]);
options.transitionStyle = IosWebViewOptionsTransitionStyle.fromValue(map["transitionStyle"]);
return options;
}
} }
\ No newline at end of file
#main-frame-error {
box-sizing: border-box;
padding: 0 10%;
font-size: 1em;
line-height: 1.55;
margin: 0 auto;
max-width: 600px;
padding-top: 100px;
width: 100%;
}
#main-content {
font-size: 1em;
line-height: 1.55;
margin: 0 auto;
max-width: 600px;
padding-top: 100px;
width: 100%;
}
#t-rex-icon {
font-size: 1em;
line-height: 1.55;
background-repeat: no-repeat;
background-size: 100%;
height: 72px;
margin: 0 0 40px;
width: 72px;
display: inline-block;
content: -webkit-image-set(
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABIAQMAAABvIyEEAAAABlBMVEUAAABTU1OoaSf/AAAAAXRSTlMAQObYZgAAAGxJREFUeF7tyMEJwkAQRuFf5ipMKxYQiJ3Z2nSwrWwBA0+DQZcdxEOueaePp9+dQZFB7GpUcURSVU66yVNFj6LFICatThZB6r/ko/pbRpUgilY0Cbw5sNmb9txGXUKyuH7eV25x39DtJXUNPQGJtWFV+BT/QAAAAABJRU5ErkJggg==)
1x,
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJAAAACQBAMAAAAVaP+LAAAAGFBMVEUAAABTU1NNTU1TU1NPT09SUlJSUlJTU1O8B7DEAAAAB3RSTlMAoArVKvVgBuEdKgAAAJ1JREFUeF7t1TEOwyAMQNG0Q6/UE+RMXD9d/tC6womIFSL9P+MnAYOXeTIzMzMzMzMzaz8J9Ri6HoITmuHXhISE8nEh9yxDh55aCEUoTGbbQwjqHwIkRAEiIaG0+0AA9VBMaE89Rogeoww936MQrWdBr4GN/z0IAdQ6nQ/FIpRXDwHcA+JIJcQowQAlFUA0MfQpXLlVQfkzR4igS6ENjknm/wiaGhsAAAAASUVORK5CYII=)
2x
);
position: relative;
visibility: hidden;
}
#offline-resources {
display: none;
}
#main-frame-error > .runner-container {
height: 150px;
max-width: 600px;
overflow: hidden;
position: absolute;
top: 35px;
width: 44px;
}
#main-frame-error > .controller {
background: rgba(247, 247, 247, 0.1);
height: 100vh;
left: 0;
position: absolute;
top: 0;
width: 100vw;
z-index: 9;
}
#main-frame-error .hidden {
display: none;
}
<div id="main-frame-error">
<div id="main-content">
<div class="icon icon-offline"></div>
</div>
<div id="offline-resources">
<img id="offline-resources-1x" src="data:image/png;base64,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">
<img id="offline-resources-2x" src="data:image/png;base64,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">
<template id="audio-resources">
<audio id="offline-sound-press" src="data:audio/mpeg;base64,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"></audio>
<audio id="offline-sound-hit" src="data:audio/mpeg;base64,T2dnUwACAAAAAAAAAABVDxppAAAAABYzHfUBHgF2b3JiaXMAAAAAAkSsAAD/////AHcBAP////+4AU9nZ1MAAAAAAAAAAAAAVQ8aaQEAAAC9PVXbEEf//////////////////+IDdm9yYmlzNwAAAEFPOyBhb1R1ViBiNSBbMjAwNjEwMjRdIChiYXNlZCBvbiBYaXBoLk9yZydzIGxpYlZvcmJpcykAAAAAAQV2b3JiaXMlQkNWAQBAAAAkcxgqRqVzFoQQGkJQGeMcQs5r7BlCTBGCHDJMW8slc5AhpKBCiFsogdCQVQAAQAAAh0F4FISKQQghhCU9WJKDJz0IIYSIOXgUhGlBCCGEEEIIIYQQQgghhEU5aJKDJ0EIHYTjMDgMg+U4+ByERTlYEIMnQegghA9CuJqDrDkIIYQkNUhQgwY56ByEwiwoioLEMLgWhAQ1KIyC5DDI1IMLQoiag0k1+BqEZ0F4FoRpQQghhCRBSJCDBkHIGIRGQViSgwY5uBSEy0GoGoQqOQgfhCA0ZBUAkAAAoKIoiqIoChAasgoAyAAAEEBRFMdxHMmRHMmxHAsIDVkFAAABAAgAAKBIiqRIjuRIkiRZkiVZkiVZkuaJqizLsizLsizLMhAasgoASAAAUFEMRXEUBwgNWQUAZAAACKA4iqVYiqVoiueIjgiEhqwCAIAAAAQAABA0Q1M8R5REz1RV17Zt27Zt27Zt27Zt27ZtW5ZlGQgNWQUAQAAAENJpZqkGiDADGQZCQ1YBAAgAAIARijDEgNCQVQAAQAAAgBhKDqIJrTnfnOOgWQ6aSrE5HZxItXmSm4q5Oeecc87J5pwxzjnnnKKcWQyaCa0555zEoFkKmgmtOeecJ7F50JoqrTnnnHHO6WCcEcY555wmrXmQmo21OeecBa1pjppLsTnnnEi5eVKbS7U555xzzjnnnHPOOeec6sXpHJwTzjnnnKi9uZab0MU555xPxunenBDOOeecc84555xzzjnnnCA0ZBUAAAQAQBCGjWHcKQjS52ggRhFiGjLpQffoMAkag5xC6tHoaKSUOggllXFSSicIDVkFAAACAEAIIYUUUkghhRRSSCGFFGKIIYYYcsopp6CCSiqpqKKMMssss8wyyyyzzDrsrLMOOwwxxBBDK63EUlNtNdZYa+4555qDtFZaa621UkoppZRSCkJDVgEAIAAABEIGGWSQUUghhRRiiCmnnHIKKqiA0JBVAAAgAIAAAAAAT/Ic0REd0REd0REd0REd0fEczxElURIlURIt0zI101NFVXVl15Z1Wbd9W9iFXfd93fd93fh1YViWZVmWZVmWZVmWZVmWZVmWIDRkFQAAAgAAIIQQQkghhRRSSCnGGHPMOegklBAIDVkFAAACAAgAAABwFEdxHMmRHEmyJEvSJM3SLE/zNE8TPVEURdM0VdEVXVE3bVE2ZdM1XVM2XVVWbVeWbVu2dduXZdv3fd/3fd/3fd/3fd/3fV0HQkNWAQASAAA6kiMpkiIpkuM4jiRJQGjIKgBABgBAAACK4iiO4ziSJEmSJWmSZ3mWqJma6ZmeKqpAaMgqAAAQAEAAAAAAAACKpniKqXiKqHiO6IiSaJmWqKmaK8qm7Lqu67qu67qu67qu67qu67qu67qu67qu67qu67qu67qu67quC4SGrAIAJAAAdCRHciRHUiRFUiRHcoDQkFUAgAwAgAAAHMMxJEVyLMvSNE/zNE8TPdETPdNTRVd0gdCQVQAAIACAAAAAAAAADMmwFMvRHE0SJdVSLVVTLdVSRdVTVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTdM0TRMIDVkJAJABAKAQW0utxdwJahxi0nLMJHROYhCqsQgiR7W3yjGlHMWeGoiUURJ7qihjiknMMbTQKSet1lI6hRSkmFMKFVIOWiA0ZIUAEJoB4HAcQLIsQLI0AAAAAAAAAJA0DdA8D7A8DwAAAAAAAAAkTQMsTwM0zwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQNI0QPM8QPM8AAAAAAAAANA8D/BEEfBEEQAAAAAAAAAszwM80QM8UQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwNE0QPM8QPM8AAAAAAAAALA8D/BEEfA8EQAAAAAAAAA0zwM8UQQ8UQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAABDgAAAQYCEUGrIiAIgTADA4DjQNmgbPAziWBc+D50EUAY5lwfPgeRBFAAAAAAAAAAAAADTPg6pCVeGqAM3zYKpQVaguAAAAAAAAAAAAAJbnQVWhqnBdgOV5MFWYKlQVAAAAAAAAAAAAAE8UobpQXbgqwDNFuCpcFaoLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAABhwAAAIMKEMFBqyIgCIEwBwOIplAQCA4ziWBQAAjuNYFgAAWJYligAAYFmaKAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAGHAAAAgwoQwUGrISAIgCADAoimUBy7IsYFmWBTTNsgCWBtA8gOcBRBEACAAAKHAAAAiwQVNicYBCQ1YCAFEAAAZFsSxNE0WapmmaJoo0TdM0TRR5nqZ5nmlC0zzPNCGKnmeaEEXPM02YpiiqKhBFVRUAAFDgAAAQYIOmxOIAhYasBABCAgAMjmJZnieKoiiKpqmqNE3TPE8URdE0VdVVaZqmeZ4oiqJpqqrq8jxNE0XTFEXTVFXXhaaJommaommqquvC80TRNE1TVVXVdeF5omiapqmqruu6EEVRNE3TVFXXdV0giqZpmqrqurIMRNE0VVVVXVeWgSiapqqqquvKMjBN01RV15VdWQaYpqq6rizLMkBVXdd1ZVm2Aarquq4ry7INcF3XlWVZtm0ArivLsmzbAgAADhwAAAKMoJOMKouw0YQLD0ChISsCgCgAAMAYphRTyjAmIaQQGsYkhBJCJiWVlEqqIKRSUikVhFRSKiWjklJqKVUQUikplQpCKqWVVAAA2IEDANiBhVBoyEoAIA8AgCBGKcYYYwwyphRjzjkHlVKKMeeck4wxxphzzkkpGWPMOeeklIw555xzUkrmnHPOOSmlc84555yUUkrnnHNOSiklhM45J6WU0jnnnBMAAFTgAAAQYKPI5gQjQYWGrAQAUgEADI5jWZqmaZ4nipYkaZrneZ4omqZmSZrmeZ4niqbJ8zxPFEXRNFWV53meKIqiaaoq1xVF0zRNVVVVsiyKpmmaquq6ME3TVFXXdWWYpmmqquu6LmzbVFXVdWUZtq2aqiq7sgxcV3Vl17aB67qu7Nq2AADwBAcAoAIbVkc4KRoLLDRkJQCQAQBAGIOMQgghhRBCCiGElFIICQAAGHAAAAgwoQwUGrISAEgFAACQsdZaa6211kBHKaWUUkqpcIxSSimllFJKKaWUUkoppZRKSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoFAC5VOADoPtiwOsJJ0VhgoSErAYBUAADAGKWYck5CKRVCjDkmIaUWK4QYc05KSjEWzzkHoZTWWiyecw5CKa3FWFTqnJSUWoqtqBQyKSml1mIQwpSUWmultSCEKqnEllprQQhdU2opltiCELa2klKMMQbhg4+xlVhqDD74IFsrMdVaAABmgwMARIINqyOcFI0FFhqyEgAICQAgjFGKMcYYc8455yRjjDHmnHMQQgihZIwx55xzDkIIIZTOOeeccxBCCCGEUkrHnHMOQgghhFBS6pxzEEIIoYQQSiqdcw5CCCGEUkpJpXMQQgihhFBCSSWl1DkIIYQQQikppZRCCCGEEkIoJaWUUgghhBBCKKGklFIKIYRSQgillJRSSimFEEoIpZSSUkkppRJKCSGEUlJJKaUUQggllFJKKimllEoJoYRSSimlpJRSSiGUUEIpBQAAHDgAAAQYQScZVRZhowkXHoBCQ1YCAGQAAJSyUkoorVVAIqUYpNpCR5mDFHOJLHMMWs2lYg4pBq2GyjGlGLQWMgiZUkxKCSV1TCknLcWYSuecpJhzjaVzEAAAAEEAgICQAAADBAUzAMDgAOFzEHQCBEcbAIAgRGaIRMNCcHhQCRARUwFAYoJCLgBUWFykXVxAlwEu6OKuAyEEIQhBLA6ggAQcnHDDE294wg1O0CkqdSAAAAAAAAwA8AAAkFwAERHRzGFkaGxwdHh8gISIjJAIAAAAAAAYAHwAACQlQERENHMYGRobHB0eHyAhIiMkAQCAAAIAAAAAIIAABAQEAAAAAAACAAAABARPZ2dTAATCMAAAAAAAAFUPGmkCAAAAhlAFnjkoHh4dHx4pKHA1KjEqLzIsNDQqMCveHiYpczUpLS4sLSg3MicsLCsqJTIvJi0sKywkMjbgWVlXWUa00CqtQNVCq7QC1aoNVPXg9Xldx3nn5tixvV6vb7TX+hg7cK21QYgAtNJFphRUtpUuMqWgsqrasj2IhOA1F7LFMdFaWzkAtNBFpisIQgtdZLqCIKjqAAa9WePLkKr1MMG1FlwGtNJFTSkIcitd1JSCIKsCAQWISK0Cyzw147T1tAK00kVNKKjQVrqoCQUVqqr412m+VKtZf9h+TDaaztAAtNJFzVQQhFa6qJkKgqAqUGgtuOa2Se5l6jeXGSqnLM9enqnLs5dn6m7TptWUiVUVN4jhUz9//lzx+Xw+X3x8fCQSiWggDAA83UXF6/vpLipe3zsCULWMBE5PMTBMlsv39/f39/f39524nZ13CDgaRFuLYTbaWgyzq22MzEyKolIpst50Z9PGqqJSq8T2++taLf3+oqg6btyouhEjYlxFjXxex1wCBFxcv+PmzG1uc2bKyJFLLlkizZozZ/ZURpZs2TKiWbNnz5rKyJItS0akWbNnzdrIyJJtxmCczpxOATRRhoPimyjDQfEfIFMprQDU3WFYbXZLZZxMhxrGyRh99Uqel55XEk+9efP7I/FU/8Ojew4JNN/rTq6b73Un1x+AVSsCWD2tNqtpGOM4DOM4GV7n5th453cXNGcfAYQKTFEOguKnKAdB8btRLxNBWUrViLoY1/q1er+Q9xkvZM/IjaoRf30xu3HLnr61fu3UBDRZHZdqsjoutQeAVesAxNMTw2rR66X/Ix6/T5tx80+t/D67ipt/q5XfJzTfa03Wzfdak/UeAEpZawlsbharxTBVO1+c2nm/7/f1XR1dY8XaKWMH3aW9xvEFRFEksXgURRKLn7VamSFRVnYXg0C2Zo2MNE3+57u+e3NFlVev1uufX6nU3Lnf9d1j4wE03+sObprvdQc3ewBYFIArAtjdrRaraRivX7x+8VrbHIofG0n6cFwtNFKYBzxXA2j4uRpAw7dJRkSETBkZV1V1o+N0Op1WhmEyDOn36437RbKvl7zz838wgn295Iv8/Ac8UaRIPFGkSHyAzCItAXY3dzGsNueM6VDDOJkOY3QYX008L6vnfZp/3qf559VQL3Xm1SEFNN2fiMA03Z+IwOwBoKplAKY4TbGIec0111x99dXr9XrjZ/nzdSWXBekAHEsWp4ljyeI0sVs2FEGiLFLj7rjxeqG8Pm+tX/uW90b+DX31bVTF/I+Ut+/sM1IA/MyILvUzI7rUbpNqyIBVjSDGVV/Jo/9H6G/jq+5y3Pzb7P74Znf5ffZtApI5/fN5SAcHjIhB5vTP5yEdHDAiBt4oK/WGeqUMMspeTNsGk/H/PziIgCrG1Rijktfreh2vn4DH78WXa25yZkizZc9oM7JmaYeZM6bJOJkOxmE69Hmp/q/k0fvVRLln3H6fXcXNPt78W638Ptlxsytv/pHyW7Pfp1Xc7L5XfqvZb5MdN7vy5p/u8lut/D6t4mb3vfmnVn6bNt9nV3Hzj1d+q9lv02bc7Mqbf6vZb+N23OzKm73u8lOz3+fY3uwqLv1022+THTepN38yf7XyW1aX8YqjACWfDTiAA+BQALTURU0oCFpLXdSEgqAJpAKxrLtzybNt1Go5VeJAASzRnh75Eu3pke8BYNWiCIBVLdgsXMqlXBJijDGW2Sj5lUqlSJFpPN9fAf08318B/ewBUMUiA3h4YGIaooZrfn5+fn5+fn5+fn6mtQYKcQE8WVg5YfJkYeWEyWqblCIiiqKoVGq1WqxWWa3X6/V6vVoty0zrptXq9/u4ccS4GjWKGxcM6ogaNWpUnoDf73Xd3OQml2xZMhJNM7Nmz54zZ/bsWbNmphVJRpYs2bJly5YtS0YSoWlm1uzZc+bMnj17ZloATNNI4PbTNBK4/W5jlJGglFJWI4hR/levXr06RuJ5+fLly6Ln1atXxxD18uXLKnr+V8cI8/M03+vErpvvdWLXewBYxVoC9bBZDcPU3Bevtc399UWNtZH0p4MJZov7AkxThBmYpggzcNVCJqxIRQwiLpNBxxqUt/NvuCqmb2Poa+RftCr7DO3te16HBjzbulL22daVsnsAqKIFwMXVzbCLYdVe9vGovzx9xP7469mk3L05d1+qjyKuPAY8397G2PPtbYztAWDVQgCH09MwTTG+Us67nX1fG5G+0o3YvspGtK+yfBmqAExTJDHQaYokBnrrZZEZkqoa3BjFDJlmGA17PF+qE/GbJd3xm0V38qoYT/aLuTzh6w/ST/j6g/QHYBVgKYHTxcVqGKY5DOM4DNNRO3OXkM0JmAto6AE01xBa5OYaQou8B4BmRssAUNQ0TfP169fv169fvz6XSIZhGIbJixcvXrzIFP7+/3/9evc/wyMAVFM8EEOvpngghr5by8hIsqiqBjXGXx0T4zCdTCfj8PJl1fy83vv7q1fHvEubn5+fnwc84etOrp/wdSfXewBUsRDA5upqMU1DNl+/GNunkTDUGrWzn0BDIC5UUw7CwKspB2HgVzVFSFZ1R9QxU8MkHXvLGV8jKxtjv6J9G0N/MX1fIysbQzTdOlK26daRsnsAWLUGWFxcTQum8Skv93j2KLpfjSeb3fvFmM3xt3L3/mwCPN/2Rvb5tjeyewBULQGmzdM0DMzS3vEVHVu6MVTZGNn3Fe37WjxU2RjqAUxThJGfpggjv1uLDAlVdeOIGNH/1P9Q5/Jxvf49nmyOj74quveLufGb4zzh685unvB1Zzd7AFQAWAhguLpaTFNk8/1i7Ni+Oq5BxQVcGABEVcgFXo+qkAu8vlurZiaoqiNi3N2Z94sXL168ePEiR4wYMWLEiBEjRowYMWLEiBEjAFRVtGm4qqJNw7ceGRkZrGpQNW58OozDOIzDy5dV8/Pz8/Pz8/Pz8/Pz8/Pz8/NlPN/rDr6f73UH33sAVLGUwHRxsxqGaq72+tcvy5LsLLZ5JdBo0BdUU7Qgr6ZoQb4NqKon4PH6zfFknHYYjOqLT9XaWdkYWvQr2vcV7fuK9n3F9AEs3SZSduk2kbJ7AKhqBeDm7maYaujzKS8/0f/UJ/eL7v2ie7/o3rfHk83xBDzdZlLu6TaTcnsAWLUAYHcz1KqivUt7V/ZQZWPoX7TvK9r3a6iyMVSJ6QNMUaSQnaJIIXvrGSkSVTWIihsZpsmYjKJ/8vTxvC6694sxm+PJ5vhbuXu/ADzf6w5+nu91Bz97AFi1lACHm9UwVHPztbbpkiKHJVsy2SAcDURTFhZc0ZSFBdeqNqiKQXwej8dxXrx48eLFixcvXrx4oY3g8/////////+voo3IF3cCRE/xjoLoKd5RsPUCKVN9jt/v8TruMJ1MJ9PJ6E3z8y9fvnz58uXLly+rSp+Z+V+9ejXv7+8eukl9XpcPJED4YJP6vC4fSIDwgWN7vdDrmfT//4PHDfg98ns9/qDHnBxps2RPkuw5ciYZOXPJmSFrllSSNVumJDNLphgno2E6GQ3jUBmPeOn/KP11zY6bfxvfjCu/TSuv/Datustxs0/Njpt9anbc7Nv4yiu/TSuv/Datustxs0/Njpt9aptx82/jm175bVp55bfZ/e5y3OxT24ybfWqbcfNv08orv00rr/w27dfsuNmnthk3+7SVV36bVl75bVqJnUxPzXazT0294mnq2W+TikmmE5LiQb3pAa94mnpFAGxeSf1/jn9mWTgDBjhUUv+f459ZFs6AAQ4AAAAAAIAH/0EYBHEAB6gDzBkAAUxWjEAQk7nWaBZuuKvBN6iqkoMah7sAhnRZ6lFjmllwEgGCAde2zYBzAB5AAH5J/X+Of81ycQZMHI0uqf/P8a9ZLs6AiaMRAAAAAAIAOPgPw0EUEIddhEaDphAAjAhrrgAUlNDwPZKFEPFz2JKV4FqHl6tIxjaQDfQAiJqgZk1GDQgcBuAAfkn9f45/zXLiDBgwuqT+P8e/ZjlxBgwYAQAAAAAAg/8fDBlCDUeGDICqAJAT585AAALkhkHxIHMR3AF8IwmgWZwQhv0DcpcIMeTjToEGKDQAB0CEACgAfkn9f45/LXLiDCiMxpfU/+f41yInzoDCaAwAAAAEg4P/wyANDgAEhDsAujhQcBgAHEakAKBZjwHgANMYAkIDo+L8wDUrrgHpWnPwBBoJGZqDBmBAUAB1QANeOf1/zn53uYQA9ckctMrp/3P2u8slBKhP5qABAAAAAACAIAyCIAiD8DAMwoADzgECAA0wQFMAiMtgo6AATVGAE0gADAQA"></audio>
<audio id="offline-sound-reached" src="data:audio/mpeg;base64,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"></audio>
</template>
</div>
</div>
<script>(function(){"use strict";function Runner(outerContainerId,opt_config){if(Runner.instance_){return Runner.instance_}Runner.instance_=this;this.outerContainerEl=document.querySelector(outerContainerId);this.containerEl=null;this.snackbarEl=null;this.touchController=null;this.config=opt_config||Runner.config;this.dimensions=Runner.defaultDimensions;this.canvas=null;this.canvasCtx=null;this.tRex=null;this.distanceMeter=null;this.distanceRan=0;this.highestScore=0;this.syncHighestScore=false;this.time=0;this.runningTime=0;this.msPerFrame=1e3/FPS;this.currentSpeed=this.config.SPEED;this.obstacles=[];this.activated=false;this.playing=false;this.crashed=false;this.paused=false;this.inverted=false;this.invertTimer=0;this.resizeTimerId_=null;this.playCount=0;this.audioBuffer=null;this.soundFx={};this.audioContext=null;this.images={};this.imagesLoaded=0;if(this.isDisabled()){this.setupDisabledRunner()}else{this.loadImages();window["initializeEasterEggHighScore"]=this.initializeHighScore.bind(this)}}window["Runner"]=Runner;var DEFAULT_WIDTH=600;var FPS=60;var IS_HIDPI=window.devicePixelRatio>1;var IS_IOS=/iPad|iPhone|iPod|MacIntel/.test(window.navigator.platform)&&!/Safari/.test(window.navigator.userAgent);var IS_MOBILE=/Android/.test(window.navigator.userAgent)||IS_IOS;var ARCADE_MODE_URL="chrome://dino/";Runner.config={ACCELERATION:.001,BG_CLOUD_SPEED:.2,BOTTOM_PAD:10,CANVAS_IN_VIEW_OFFSET:-10,CLEAR_TIME:3e3,CLOUD_FREQUENCY:.5,GAMEOVER_CLEAR_TIME:750,GAP_COEFFICIENT:.6,GRAVITY:.6,INITIAL_JUMP_VELOCITY:12,INVERT_FADE_DURATION:12e3,INVERT_DISTANCE:700,MAX_BLINK_COUNT:3,MAX_CLOUDS:6,MAX_OBSTACLE_LENGTH:3,MAX_OBSTACLE_DUPLICATION:2,MAX_SPEED:13,MIN_JUMP_HEIGHT:35,MOBILE_SPEED_COEFFICIENT:1.2,RESOURCE_TEMPLATE_ID:"audio-resources",SPEED:6,SPEED_DROP_COEFFICIENT:3,ARCADE_MODE_INITIAL_TOP_POSITION:35,ARCADE_MODE_TOP_POSITION_PERCENT:.1};Runner.defaultDimensions={WIDTH:DEFAULT_WIDTH,HEIGHT:150};Runner.classes={ARCADE_MODE:"arcade-mode",CANVAS:"runner-canvas",CONTAINER:"runner-container",CRASHED:"crashed",ICON:"icon-offline",INVERTED:"inverted",SNACKBAR:"snackbar",SNACKBAR_SHOW:"snackbar-show",TOUCH_CONTROLLER:"controller"};Runner.spriteDefinition={LDPI:{CACTUS_LARGE:{x:332,y:2},CACTUS_SMALL:{x:228,y:2},CLOUD:{x:86,y:2},HORIZON:{x:2,y:54},MOON:{x:484,y:2},PTERODACTYL:{x:134,y:2},RESTART:{x:2,y:2},TEXT_SPRITE:{x:655,y:2},TREX:{x:848,y:2},STAR:{x:645,y:2}},HDPI:{CACTUS_LARGE:{x:652,y:2},CACTUS_SMALL:{x:446,y:2},CLOUD:{x:166,y:2},HORIZON:{x:2,y:104},MOON:{x:954,y:2},PTERODACTYL:{x:260,y:2},RESTART:{x:2,y:2},TEXT_SPRITE:{x:1294,y:2},TREX:{x:1678,y:2},STAR:{x:1276,y:2}}};Runner.sounds={BUTTON_PRESS:"offline-sound-press",HIT:"offline-sound-hit",SCORE:"offline-sound-reached"};Runner.keycodes={JUMP:{38:1,32:1},DUCK:{40:1},RESTART:{13:1}};Runner.events={ANIM_END:"webkitAnimationEnd",CLICK:"click",KEYDOWN:"keydown",KEYUP:"keyup",POINTERDOWN:"pointerdown",POINTERUP:"pointerup",RESIZE:"resize",TOUCHEND:"touchend",TOUCHSTART:"touchstart",VISIBILITY:"visibilitychange",BLUR:"blur",FOCUS:"focus",LOAD:"load"};Runner.prototype={isDisabled:function(){return false},setupDisabledRunner:function(){this.containerEl=document.createElement("div");this.containerEl.className=Runner.classes.SNACKBAR;this.containerEl.textContent=false;this.outerContainerEl.appendChild(this.containerEl);document.addEventListener(Runner.events.KEYDOWN,function(e){if(Runner.keycodes.JUMP[e.keyCode]){this.containerEl.classList.add(Runner.classes.SNACKBAR_SHOW);document.querySelector(".icon").classList.add("icon-disabled")}}.bind(this))},updateConfigSetting:function(setting,value){if(setting in this.config&&value!=undefined){this.config[setting]=value;switch(setting){case"GRAVITY":case"MIN_JUMP_HEIGHT":case"SPEED_DROP_COEFFICIENT":this.tRex.config[setting]=value;break;case"INITIAL_JUMP_VELOCITY":this.tRex.setJumpVelocity(value);break;case"SPEED":this.setSpeed(value);break}}},loadImages:function(){if(IS_HIDPI){Runner.imageSprite=document.getElementById("offline-resources-2x");this.spriteDef=Runner.spriteDefinition.HDPI}else{Runner.imageSprite=document.getElementById("offline-resources-1x");this.spriteDef=Runner.spriteDefinition.LDPI}if(Runner.imageSprite.complete){this.init()}else{Runner.imageSprite.addEventListener(Runner.events.LOAD,this.init.bind(this))}},loadSounds:function(){if(!IS_IOS){this.audioContext=new AudioContext;var resourceTemplate=document.getElementById(this.config.RESOURCE_TEMPLATE_ID).content;for(var sound in Runner.sounds){var soundSrc=resourceTemplate.getElementById(Runner.sounds[sound]).src;soundSrc=soundSrc.substr(soundSrc.indexOf(",")+1);var buffer=decodeBase64ToArrayBuffer(soundSrc);this.audioContext.decodeAudioData(buffer,function(index,audioData){this.soundFx[index]=audioData}.bind(this,sound))}}},setSpeed:function(opt_speed){var speed=opt_speed||this.currentSpeed;if(this.dimensions.WIDTH<DEFAULT_WIDTH){var mobileSpeed=speed*this.dimensions.WIDTH/DEFAULT_WIDTH*this.config.MOBILE_SPEED_COEFFICIENT;this.currentSpeed=mobileSpeed>speed?speed:mobileSpeed}else if(opt_speed){this.currentSpeed=opt_speed}},init:function(){document.querySelector("."+Runner.classes.ICON).style.visibility="hidden";this.adjustDimensions();this.setSpeed();this.containerEl=document.createElement("div");this.containerEl.className=Runner.classes.CONTAINER;this.canvas=createCanvas(this.containerEl,this.dimensions.WIDTH,this.dimensions.HEIGHT,Runner.classes.PLAYER);this.canvasCtx=this.canvas.getContext("2d");this.canvasCtx.fillStyle="#f7f7f7";this.canvasCtx.fill();Runner.updateCanvasScaling(this.canvas);this.horizon=new Horizon(this.canvas,this.spriteDef,this.dimensions,this.config.GAP_COEFFICIENT);this.distanceMeter=new DistanceMeter(this.canvas,this.spriteDef.TEXT_SPRITE,this.dimensions.WIDTH);this.tRex=new Trex(this.canvas,this.spriteDef.TREX);this.outerContainerEl.appendChild(this.containerEl);this.startListening();this.update();window.addEventListener(Runner.events.RESIZE,this.debounceResize.bind(this))},createTouchController:function(){this.touchController=document.createElement("div");this.touchController.className=Runner.classes.TOUCH_CONTROLLER;this.touchController.addEventListener(Runner.events.TOUCHSTART,this);this.touchController.addEventListener(Runner.events.TOUCHEND,this);this.outerContainerEl.appendChild(this.touchController)},debounceResize:function(){if(!this.resizeTimerId_){this.resizeTimerId_=setInterval(this.adjustDimensions.bind(this),250)}},adjustDimensions:function(){clearInterval(this.resizeTimerId_);this.resizeTimerId_=null;var boxStyles=window.getComputedStyle(this.outerContainerEl);var padding=Number(boxStyles.paddingLeft.substr(0,boxStyles.paddingLeft.length-2));this.dimensions.WIDTH=this.outerContainerEl.offsetWidth-padding*2;if(this.isArcadeMode()){this.dimensions.WIDTH=Math.min(DEFAULT_WIDTH,this.dimensions.WIDTH);if(this.activated){this.setArcadeModeContainerScale()}}if(this.canvas){this.canvas.width=this.dimensions.WIDTH;this.canvas.height=this.dimensions.HEIGHT;Runner.updateCanvasScaling(this.canvas);this.distanceMeter.calcXPos(this.dimensions.WIDTH);this.clearCanvas();this.horizon.update(0,0,true);this.tRex.update(0);if(this.playing||this.crashed||this.paused){this.containerEl.style.width=this.dimensions.WIDTH+"px";this.containerEl.style.height=this.dimensions.HEIGHT+"px";this.distanceMeter.update(0,Math.ceil(this.distanceRan));this.stop()}else{this.tRex.draw(0,0)}if(this.crashed&&this.gameOverPanel){this.gameOverPanel.updateDimensions(this.dimensions.WIDTH);this.gameOverPanel.draw()}}},playIntro:function(){if(!this.activated&&!this.crashed){this.playingIntro=true;this.tRex.playingIntro=true;var keyframes="@-webkit-keyframes intro { "+"from { width:"+Trex.config.WIDTH+"px }"+"to { width: "+this.dimensions.WIDTH+"px }"+"}";document.styleSheets[0].insertRule(keyframes,0);this.containerEl.addEventListener(Runner.events.ANIM_END,this.startGame.bind(this));this.containerEl.style.webkitAnimation="intro .4s ease-out 1 both";this.containerEl.style.width=this.dimensions.WIDTH+"px";this.setPlayStatus(true);this.activated=true}else if(this.crashed){this.restart()}},startGame:function(){if(this.isArcadeMode()){this.setArcadeMode()}this.runningTime=0;this.playingIntro=false;this.tRex.playingIntro=false;this.containerEl.style.webkitAnimation="";this.playCount++;document.addEventListener(Runner.events.VISIBILITY,this.onVisibilityChange.bind(this));window.addEventListener(Runner.events.BLUR,this.onVisibilityChange.bind(this));window.addEventListener(Runner.events.FOCUS,this.onVisibilityChange.bind(this))},clearCanvas:function(){this.canvasCtx.clearRect(0,0,this.dimensions.WIDTH,this.dimensions.HEIGHT)},isCanvasInView:function(){return this.containerEl.getBoundingClientRect().top>Runner.config.CANVAS_IN_VIEW_OFFSET},update:function(){this.updatePending=false;var now=getTimeStamp();var deltaTime=now-(this.time||now);this.time=now;if(this.playing){this.clearCanvas();if(this.tRex.jumping){this.tRex.updateJump(deltaTime)}this.runningTime+=deltaTime;var hasObstacles=this.runningTime>this.config.CLEAR_TIME;if(this.tRex.jumpCount==1&&!this.playingIntro){this.playIntro()}if(this.playingIntro){this.horizon.update(0,this.currentSpeed,hasObstacles)}else{deltaTime=!this.activated?0:deltaTime;this.horizon.update(deltaTime,this.currentSpeed,hasObstacles,this.inverted)}var collision=hasObstacles&&checkForCollision(this.horizon.obstacles[0],this.tRex);if(!collision){this.distanceRan+=this.currentSpeed*deltaTime/this.msPerFrame;if(this.currentSpeed<this.config.MAX_SPEED){this.currentSpeed+=this.config.ACCELERATION}}else{this.gameOver()}var playAchievementSound=this.distanceMeter.update(deltaTime,Math.ceil(this.distanceRan));if(playAchievementSound){this.playSound(this.soundFx.SCORE)}if(this.invertTimer>this.config.INVERT_FADE_DURATION){this.invertTimer=0;this.invertTrigger=false;this.invert()}else if(this.invertTimer){this.invertTimer+=deltaTime}else{var actualDistance=this.distanceMeter.getActualDistance(Math.ceil(this.distanceRan));if(actualDistance>0){this.invertTrigger=!(actualDistance%this.config.INVERT_DISTANCE);if(this.invertTrigger&&this.invertTimer===0){this.invertTimer+=deltaTime;this.invert()}}}}if(this.playing||!this.activated&&this.tRex.blinkCount<Runner.config.MAX_BLINK_COUNT){this.tRex.update(deltaTime);this.scheduleNextUpdate()}},handleEvent:function(e){return function(evtType,events){switch(evtType){case events.KEYDOWN:case events.TOUCHSTART:case events.POINTERDOWN:this.onKeyDown(e);break;case events.KEYUP:case events.TOUCHEND:case events.POINTERUP:this.onKeyUp(e);break}}.bind(this)(e.type,Runner.events)},startListening:function(){document.addEventListener(Runner.events.KEYDOWN,this);document.addEventListener(Runner.events.KEYUP,this);this.containerEl.addEventListener(Runner.events.TOUCHSTART,this);document.addEventListener(Runner.events.POINTERDOWN,this);document.addEventListener(Runner.events.POINTERUP,this)},stopListening:function(){document.removeEventListener(Runner.events.KEYDOWN,this);document.removeEventListener(Runner.events.KEYUP,this);if(this.touchController){this.touchController.removeEventListener(Runner.events.TOUCHSTART,this);this.touchController.removeEventListener(Runner.events.TOUCHEND,this)}this.containerEl.removeEventListener(Runner.events.TOUCHSTART,this);document.removeEventListener(Runner.events.POINTERDOWN,this);document.removeEventListener(Runner.events.POINTERUP,this)},onKeyDown:function(e){if(IS_MOBILE&&this.playing){e.preventDefault()}if(this.isCanvasInView()){if(!this.crashed&&!this.paused){if(Runner.keycodes.JUMP[e.keyCode]||e.type==Runner.events.TOUCHSTART){e.preventDefault();if(!this.playing){if(!this.touchController&&e.type==Runner.events.TOUCHSTART){this.createTouchController()}this.loadSounds();this.setPlayStatus(true);this.update();if(window.errorPageController){errorPageController.trackEasterEgg()}}if(!this.tRex.jumping&&!this.tRex.ducking){this.playSound(this.soundFx.BUTTON_PRESS);this.tRex.startJump(this.currentSpeed)}}else if(this.playing&&Runner.keycodes.DUCK[e.keyCode]){e.preventDefault();if(this.tRex.jumping){this.tRex.setSpeedDrop()}else if(!this.tRex.jumping&&!this.tRex.ducking){this.tRex.setDuck(true)}}}else if(IS_IOS&&this.crashed&&e.type==Runner.events.TOUCHSTART&&e.currentTarget==this.containerEl){this.handleGameOverClicks(e)}}},onKeyUp:function(e){var keyCode=String(e.keyCode);var isjumpKey=Runner.keycodes.JUMP[keyCode]||e.type==Runner.events.TOUCHEND||e.type==Runner.events.POINTERUP;if(this.isRunning()&&isjumpKey){this.tRex.endJump()}else if(Runner.keycodes.DUCK[keyCode]){this.tRex.speedDrop=false;this.tRex.setDuck(false)}else if(this.crashed){var deltaTime=getTimeStamp()-this.time;if(this.isCanvasInView()&&(Runner.keycodes.RESTART[keyCode]||this.isLeftClickOnCanvas(e)||deltaTime>=this.config.GAMEOVER_CLEAR_TIME&&Runner.keycodes.JUMP[keyCode])){this.handleGameOverClicks(e)}}else if(this.paused&&isjumpKey){this.tRex.reset();this.play()}},handleGameOverClicks:function(e){e.preventDefault();if(this.distanceMeter.hasClickedOnHighScore(e)&&this.highestScore){if(this.distanceMeter.isHighScoreFlashing()){this.saveHighScore(0,true);this.distanceMeter.resetHighScore()}else{this.distanceMeter.startHighScoreFlashing()}}else{this.distanceMeter.cancelHighScoreFlashing();this.restart()}},isLeftClickOnCanvas:function(e){return e.button!=null&&e.button<2&&e.type==Runner.events.POINTERUP&&e.target==this.canvas},scheduleNextUpdate:function(){if(!this.updatePending){this.updatePending=true;this.raqId=requestAnimationFrame(this.update.bind(this))}},isRunning:function(){return!!this.raqId},initializeHighScore:function(highScore){this.syncHighestScore=true;highScore=Math.ceil(highScore);if(highScore<this.highestScore){if(window.errorPageController){errorPageController.updateEasterEggHighScore(this.highestScore)}return}this.highestScore=highScore;this.distanceMeter.setHighScore(this.highestScore)},saveHighScore:function(distanceRan,opt_resetScore){this.highestScore=Math.ceil(distanceRan);this.distanceMeter.setHighScore(this.highestScore);if(this.syncHighestScore&&window.errorPageController){if(opt_resetScore){errorPageController.resetEasterEggHighScore()}else{errorPageController.updateEasterEggHighScore(this.highestScore)}}},gameOver:function(){this.playSound(this.soundFx.HIT);vibrate(200);this.stop();this.crashed=true;this.distanceMeter.achievement=false;this.tRex.update(100,Trex.status.CRASHED);if(!this.gameOverPanel){this.gameOverPanel=new GameOverPanel(this.canvas,this.spriteDef.TEXT_SPRITE,this.spriteDef.RESTART,this.dimensions)}else{this.gameOverPanel.draw()}if(this.distanceRan>this.highestScore){this.saveHighScore(this.distanceRan)}this.time=getTimeStamp()},stop:function(){this.setPlayStatus(false);this.paused=true;cancelAnimationFrame(this.raqId);this.raqId=0},play:function(){if(!this.crashed){this.setPlayStatus(true);this.paused=false;this.tRex.update(0,Trex.status.RUNNING);this.time=getTimeStamp();this.update()}},restart:function(){if(!this.raqId){this.playCount++;this.runningTime=0;this.setPlayStatus(true);this.paused=false;this.crashed=false;this.distanceRan=0;this.setSpeed(this.config.SPEED);this.time=getTimeStamp();this.containerEl.classList.remove(Runner.classes.CRASHED);this.clearCanvas();this.distanceMeter.reset(this.highestScore);this.horizon.reset();this.tRex.reset();this.playSound(this.soundFx.BUTTON_PRESS);this.invert(true);this.bdayFlashTimer=null;this.update()}},setPlayStatus:function(isPlaying){if(this.touchController)this.touchController.classList.toggle("hidden",!isPlaying);this.playing=isPlaying},isArcadeMode:function(){return document.title==ARCADE_MODE_URL},setArcadeMode:function(){document.body.classList.add(Runner.classes.ARCADE_MODE);this.setArcadeModeContainerScale()},setArcadeModeContainerScale:function(){var windowHeight=window.innerHeight;var scaleHeight=windowHeight/this.dimensions.HEIGHT;var scaleWidth=window.innerWidth/this.dimensions.WIDTH;var scale=Math.max(1,Math.min(scaleHeight,scaleWidth));var scaledCanvasHeight=this.dimensions.HEIGHT*scale;var translateY=Math.ceil(Math.max(0,(windowHeight-scaledCanvasHeight-Runner.config.ARCADE_MODE_INITIAL_TOP_POSITION)*Runner.config.ARCADE_MODE_TOP_POSITION_PERCENT))*window.devicePixelRatio;this.containerEl.style.transform="scale("+scale+") translateY("+translateY+"px)"},onVisibilityChange:function(e){if(document.hidden||document.webkitHidden||e.type=="blur"||document.visibilityState!="visible"){this.stop()}else if(!this.crashed){this.tRex.reset();this.play()}},playSound:function(soundBuffer){if(soundBuffer){var sourceNode=this.audioContext.createBufferSource();sourceNode.buffer=soundBuffer;sourceNode.connect(this.audioContext.destination);sourceNode.start(0)}},invert:function(reset){let htmlEl=document.firstElementChild;if(reset){htmlEl.classList.toggle(Runner.classes.INVERTED,false);this.invertTimer=0;this.inverted=false}else{this.inverted=htmlEl.classList.toggle(Runner.classes.INVERTED,this.invertTrigger)}}};Runner.updateCanvasScaling=function(canvas,opt_width,opt_height){var context=canvas.getContext("2d");var devicePixelRatio=Math.floor(window.devicePixelRatio)||1;var backingStoreRatio=Math.floor(context.webkitBackingStorePixelRatio)||1;var ratio=devicePixelRatio/backingStoreRatio;if(devicePixelRatio!==backingStoreRatio){var oldWidth=opt_width||canvas.width;var oldHeight=opt_height||canvas.height;canvas.width=oldWidth*ratio;canvas.height=oldHeight*ratio;canvas.style.width=oldWidth+"px";canvas.style.height=oldHeight+"px";context.scale(ratio,ratio);return true}else if(devicePixelRatio==1){canvas.style.width=canvas.width+"px";canvas.style.height=canvas.height+"px"}return false};function getRandomNum(min,max){return Math.floor(Math.random()*(max-min+1))+min}function vibrate(duration){if(IS_MOBILE&&window.navigator.vibrate){window.navigator.vibrate(duration)}}function createCanvas(container,width,height,opt_classname){var canvas=document.createElement("canvas");canvas.className=opt_classname?Runner.classes.CANVAS+" "+opt_classname:Runner.classes.CANVAS;canvas.width=width;canvas.height=height;container.appendChild(canvas);return canvas}function decodeBase64ToArrayBuffer(base64String){var len=base64String.length/4*3;var str=atob(base64String);var arrayBuffer=new ArrayBuffer(len);var bytes=new Uint8Array(arrayBuffer);for(var i=0;i<len;i++){bytes[i]=str.charCodeAt(i)}return bytes.buffer}function getTimeStamp(){return IS_IOS?(new Date).getTime():performance.now()}function GameOverPanel(canvas,textImgPos,restartImgPos,dimensions){this.canvas=canvas;this.canvasCtx=canvas.getContext("2d");this.canvasDimensions=dimensions;this.textImgPos=textImgPos;this.restartImgPos=restartImgPos;this.draw()}GameOverPanel.dimensions={TEXT_X:0,TEXT_Y:13,TEXT_WIDTH:191,TEXT_HEIGHT:11,RESTART_WIDTH:36,RESTART_HEIGHT:32};GameOverPanel.prototype={updateDimensions:function(width,opt_height){this.canvasDimensions.WIDTH=width;if(opt_height){this.canvasDimensions.HEIGHT=opt_height}},draw:function(){var dimensions=GameOverPanel.dimensions;var centerX=this.canvasDimensions.WIDTH/2;var textSourceX=dimensions.TEXT_X;var textSourceY=dimensions.TEXT_Y;var textSourceWidth=dimensions.TEXT_WIDTH;var textSourceHeight=dimensions.TEXT_HEIGHT;var textTargetX=Math.round(centerX-dimensions.TEXT_WIDTH/2);var textTargetY=Math.round((this.canvasDimensions.HEIGHT-25)/3);var textTargetWidth=dimensions.TEXT_WIDTH;var textTargetHeight=dimensions.TEXT_HEIGHT;var restartSourceWidth=dimensions.RESTART_WIDTH;var restartSourceHeight=dimensions.RESTART_HEIGHT;var restartTargetX=centerX-dimensions.RESTART_WIDTH/2;var restartTargetY=this.canvasDimensions.HEIGHT/2;if(IS_HIDPI){textSourceY*=2;textSourceX*=2;textSourceWidth*=2;textSourceHeight*=2;restartSourceWidth*=2;restartSourceHeight*=2}textSourceX+=this.textImgPos.x;textSourceY+=this.textImgPos.y;this.canvasCtx.drawImage(Runner.imageSprite,textSourceX,textSourceY,textSourceWidth,textSourceHeight,textTargetX,textTargetY,textTargetWidth,textTargetHeight);this.canvasCtx.drawImage(Runner.imageSprite,this.restartImgPos.x,this.restartImgPos.y,restartSourceWidth,restartSourceHeight,restartTargetX,restartTargetY,dimensions.RESTART_WIDTH,dimensions.RESTART_HEIGHT)}};function checkForCollision(obstacle,tRex,opt_canvasCtx){var obstacleBoxXPos=Runner.defaultDimensions.WIDTH+obstacle.xPos;var tRexBox=new CollisionBox(tRex.xPos+1,tRex.yPos+1,tRex.config.WIDTH-2,tRex.config.HEIGHT-2);var obstacleBox=new CollisionBox(obstacle.xPos+1,obstacle.yPos+1,obstacle.typeConfig.width*obstacle.size-2,obstacle.typeConfig.height-2);if(opt_canvasCtx){drawCollisionBoxes(opt_canvasCtx,tRexBox,obstacleBox)}if(boxCompare(tRexBox,obstacleBox)){var collisionBoxes=obstacle.collisionBoxes;var tRexCollisionBoxes=tRex.ducking?Trex.collisionBoxes.DUCKING:Trex.collisionBoxes.RUNNING;for(var t=0;t<tRexCollisionBoxes.length;t++){for(var i=0;i<collisionBoxes.length;i++){var adjTrexBox=createAdjustedCollisionBox(tRexCollisionBoxes[t],tRexBox);var adjObstacleBox=createAdjustedCollisionBox(collisionBoxes[i],obstacleBox);var crashed=boxCompare(adjTrexBox,adjObstacleBox);if(opt_canvasCtx){drawCollisionBoxes(opt_canvasCtx,adjTrexBox,adjObstacleBox)}if(crashed){return[adjTrexBox,adjObstacleBox]}}}}return false}function createAdjustedCollisionBox(box,adjustment){return new CollisionBox(box.x+adjustment.x,box.y+adjustment.y,box.width,box.height)}function drawCollisionBoxes(canvasCtx,tRexBox,obstacleBox){canvasCtx.save();canvasCtx.strokeStyle="#f00";canvasCtx.strokeRect(tRexBox.x,tRexBox.y,tRexBox.width,tRexBox.height);canvasCtx.strokeStyle="#0f0";canvasCtx.strokeRect(obstacleBox.x,obstacleBox.y,obstacleBox.width,obstacleBox.height);canvasCtx.restore()}function boxCompare(tRexBox,obstacleBox){var crashed=false;var tRexBoxX=tRexBox.x;var tRexBoxY=tRexBox.y;var obstacleBoxX=obstacleBox.x;var obstacleBoxY=obstacleBox.y;if(tRexBox.x<obstacleBoxX+obstacleBox.width&&tRexBox.x+tRexBox.width>obstacleBoxX&&tRexBox.y<obstacleBox.y+obstacleBox.height&&tRexBox.height+tRexBox.y>obstacleBox.y){crashed=true}return crashed}function CollisionBox(x,y,w,h){this.x=x;this.y=y;this.width=w;this.height=h}function Obstacle(canvasCtx,type,spriteImgPos,dimensions,gapCoefficient,speed,opt_xOffset){this.canvasCtx=canvasCtx;this.spritePos=spriteImgPos;this.typeConfig=type;this.gapCoefficient=gapCoefficient;this.size=getRandomNum(1,Obstacle.MAX_OBSTACLE_LENGTH);this.dimensions=dimensions;this.remove=false;this.xPos=dimensions.WIDTH+(opt_xOffset||0);this.yPos=0;this.width=0;this.collisionBoxes=[];this.gap=0;this.speedOffset=0;this.currentFrame=0;this.timer=0;this.init(speed)}Obstacle.MAX_GAP_COEFFICIENT=1.5;Obstacle.MAX_OBSTACLE_LENGTH=3,Obstacle.prototype={init:function(speed){this.cloneCollisionBoxes();if(this.size>1&&this.typeConfig.multipleSpeed>speed){this.size=1}this.width=this.typeConfig.width*this.size;if(Array.isArray(this.typeConfig.yPos)){var yPosConfig=IS_MOBILE?this.typeConfig.yPosMobile:this.typeConfig.yPos;this.yPos=yPosConfig[getRandomNum(0,yPosConfig.length-1)]}else{this.yPos=this.typeConfig.yPos}this.draw();if(this.size>1){this.collisionBoxes[1].width=this.width-this.collisionBoxes[0].width-this.collisionBoxes[2].width;this.collisionBoxes[2].x=this.width-this.collisionBoxes[2].width}if(this.typeConfig.speedOffset){this.speedOffset=Math.random()>.5?this.typeConfig.speedOffset:-this.typeConfig.speedOffset}this.gap=this.getGap(this.gapCoefficient,speed)},draw:function(){var sourceWidth=this.typeConfig.width;var sourceHeight=this.typeConfig.height;if(IS_HIDPI){sourceWidth=sourceWidth*2;sourceHeight=sourceHeight*2}var sourceX=sourceWidth*this.size*(.5*(this.size-1))+this.spritePos.x;if(this.currentFrame>0){sourceX+=sourceWidth*this.currentFrame}this.canvasCtx.drawImage(Runner.imageSprite,sourceX,this.spritePos.y,sourceWidth*this.size,sourceHeight,this.xPos,this.yPos,this.typeConfig.width*this.size,this.typeConfig.height)},update:function(deltaTime,speed){if(!this.remove){if(this.typeConfig.speedOffset){speed+=this.speedOffset}this.xPos-=Math.floor(speed*FPS/1e3*deltaTime);if(this.typeConfig.numFrames){this.timer+=deltaTime;if(this.timer>=this.typeConfig.frameRate){this.currentFrame=this.currentFrame==this.typeConfig.numFrames-1?0:this.currentFrame+1;this.timer=0}}this.draw();if(!this.isVisible()){this.remove=true}}},getGap:function(gapCoefficient,speed){var minGap=Math.round(this.width*speed+this.typeConfig.minGap*gapCoefficient);var maxGap=Math.round(minGap*Obstacle.MAX_GAP_COEFFICIENT);return getRandomNum(minGap,maxGap)},isVisible:function(){return this.xPos+this.width>0},cloneCollisionBoxes:function(){var collisionBoxes=this.typeConfig.collisionBoxes;for(var i=collisionBoxes.length-1;i>=0;i--){this.collisionBoxes[i]=new CollisionBox(collisionBoxes[i].x,collisionBoxes[i].y,collisionBoxes[i].width,collisionBoxes[i].height)}}};Obstacle.types=[{type:"CACTUS_SMALL",width:17,height:35,yPos:105,multipleSpeed:4,minGap:120,minSpeed:0,collisionBoxes:[new CollisionBox(0,7,5,27),new CollisionBox(4,0,6,34),new CollisionBox(10,4,7,14)]},{type:"CACTUS_LARGE",width:25,height:50,yPos:90,multipleSpeed:7,minGap:120,minSpeed:0,collisionBoxes:[new CollisionBox(0,12,7,38),new CollisionBox(8,0,7,49),new CollisionBox(13,10,10,38)]},{type:"PTERODACTYL",width:46,height:40,yPos:[100,75,50],yPosMobile:[100,50],multipleSpeed:999,minSpeed:8.5,minGap:150,collisionBoxes:[new CollisionBox(15,15,16,5),new CollisionBox(18,21,24,6),new CollisionBox(2,14,4,3),new CollisionBox(6,10,4,7),new CollisionBox(10,8,6,9)],numFrames:2,frameRate:1e3/6,speedOffset:.8}];function Trex(canvas,spritePos){this.canvas=canvas;this.canvasCtx=canvas.getContext("2d");this.spritePos=spritePos;this.xPos=0;this.yPos=0;this.groundYPos=0;this.currentFrame=0;this.currentAnimFrames=[];this.blinkDelay=0;this.blinkCount=0;this.animStartTime=0;this.timer=0;this.msPerFrame=1e3/FPS;this.config=Trex.config;this.status=Trex.status.WAITING;this.jumping=false;this.ducking=false;this.jumpVelocity=0;this.reachedMinHeight=false;this.speedDrop=false;this.jumpCount=0;this.jumpspotX=0;this.init()}Trex.config={DROP_VELOCITY:-5,GRAVITY:.6,HEIGHT:47,HEIGHT_DUCK:25,INIITAL_JUMP_VELOCITY:-10,INTRO_DURATION:1500,MAX_JUMP_HEIGHT:30,MIN_JUMP_HEIGHT:30,SPEED_DROP_COEFFICIENT:3,SPRITE_WIDTH:262,START_X_POS:50,WIDTH:44,WIDTH_DUCK:59};Trex.collisionBoxes={DUCKING:[new CollisionBox(1,18,55,25)],RUNNING:[new CollisionBox(22,0,17,16),new CollisionBox(1,18,30,9),new CollisionBox(10,35,14,8),new CollisionBox(1,24,29,5),new CollisionBox(5,30,21,4),new CollisionBox(9,34,15,4)]};Trex.status={CRASHED:"CRASHED",DUCKING:"DUCKING",JUMPING:"JUMPING",RUNNING:"RUNNING",WAITING:"WAITING"};Trex.BLINK_TIMING=7e3;Trex.animFrames={WAITING:{frames:[44,0],msPerFrame:1e3/3},RUNNING:{frames:[88,132],msPerFrame:1e3/12},CRASHED:{frames:[220],msPerFrame:1e3/60},JUMPING:{frames:[0],msPerFrame:1e3/60},DUCKING:{frames:[264,323],msPerFrame:1e3/8}};Trex.prototype={init:function(){this.groundYPos=Runner.defaultDimensions.HEIGHT-this.config.HEIGHT-Runner.config.BOTTOM_PAD;this.yPos=this.groundYPos;this.minJumpHeight=this.groundYPos-this.config.MIN_JUMP_HEIGHT;this.draw(0,0);this.update(0,Trex.status.WAITING)},setJumpVelocity:function(setting){this.config.INIITAL_JUMP_VELOCITY=-setting;this.config.DROP_VELOCITY=-setting/2},update:function(deltaTime,opt_status){this.timer+=deltaTime;if(opt_status){this.status=opt_status;this.currentFrame=0;this.msPerFrame=Trex.animFrames[opt_status].msPerFrame;this.currentAnimFrames=Trex.animFrames[opt_status].frames;if(opt_status==Trex.status.WAITING){this.animStartTime=getTimeStamp();this.setBlinkDelay()}}if(this.playingIntro&&this.xPos<this.config.START_X_POS){this.xPos+=Math.round(this.config.START_X_POS/this.config.INTRO_DURATION*deltaTime)}if(this.status==Trex.status.WAITING){this.blink(getTimeStamp())}else{this.draw(this.currentAnimFrames[this.currentFrame],0)}if(this.timer>=this.msPerFrame){this.currentFrame=this.currentFrame==this.currentAnimFrames.length-1?0:this.currentFrame+1;this.timer=0}if(this.speedDrop&&this.yPos==this.groundYPos){this.speedDrop=false;this.setDuck(true)}},draw:function(x,y){var sourceX=x;var sourceY=y;var sourceWidth=this.ducking&&this.status!=Trex.status.CRASHED?this.config.WIDTH_DUCK:this.config.WIDTH;var sourceHeight=this.config.HEIGHT;var outputHeight=sourceHeight;if(IS_HIDPI){sourceX*=2;sourceY*=2;sourceWidth*=2;sourceHeight*=2}sourceX+=this.spritePos.x;sourceY+=this.spritePos.y;if(this.ducking&&this.status!=Trex.status.CRASHED){this.canvasCtx.drawImage(Runner.imageSprite,sourceX,sourceY,sourceWidth,sourceHeight,this.xPos,this.yPos,this.config.WIDTH_DUCK,outputHeight)}else{if(this.ducking&&this.status==Trex.status.CRASHED){this.xPos++}this.canvasCtx.drawImage(Runner.imageSprite,sourceX,sourceY,sourceWidth,sourceHeight,this.xPos,this.yPos,this.config.WIDTH,outputHeight)}this.canvasCtx.globalAlpha=1},setBlinkDelay:function(){this.blinkDelay=Math.ceil(Math.random()*Trex.BLINK_TIMING)},blink:function(time){var deltaTime=time-this.animStartTime;if(deltaTime>=this.blinkDelay){this.draw(this.currentAnimFrames[this.currentFrame],0);if(this.currentFrame==1){this.setBlinkDelay();this.animStartTime=time;this.blinkCount++}}},startJump:function(speed){if(!this.jumping){this.update(0,Trex.status.JUMPING);this.jumpVelocity=this.config.INIITAL_JUMP_VELOCITY-speed/10;this.jumping=true;this.reachedMinHeight=false;this.speedDrop=false}},endJump:function(){if(this.reachedMinHeight&&this.jumpVelocity<this.config.DROP_VELOCITY){this.jumpVelocity=this.config.DROP_VELOCITY}},updateJump:function(deltaTime,speed){var msPerFrame=Trex.animFrames[this.status].msPerFrame;var framesElapsed=deltaTime/msPerFrame;if(this.speedDrop){this.yPos+=Math.round(this.jumpVelocity*this.config.SPEED_DROP_COEFFICIENT*framesElapsed)}else{this.yPos+=Math.round(this.jumpVelocity*framesElapsed)}this.jumpVelocity+=this.config.GRAVITY*framesElapsed;if(this.yPos<this.minJumpHeight||this.speedDrop){this.reachedMinHeight=true}if(this.yPos<this.config.MAX_JUMP_HEIGHT||this.speedDrop){this.endJump()}if(this.yPos>this.groundYPos){this.reset();this.jumpCount++}},setSpeedDrop:function(){this.speedDrop=true;this.jumpVelocity=1},setDuck:function(isDucking){if(isDucking&&this.status!=Trex.status.DUCKING){this.update(0,Trex.status.DUCKING);this.ducking=true}else if(this.status==Trex.status.DUCKING){this.update(0,Trex.status.RUNNING);this.ducking=false}},reset:function(){this.yPos=this.groundYPos;this.jumpVelocity=0;this.jumping=false;this.ducking=false;this.update(0,Trex.status.RUNNING);this.midair=false;this.speedDrop=false;this.jumpCount=0}};function DistanceMeter(canvas,spritePos,canvasWidth){this.canvas=canvas;this.canvasCtx=canvas.getContext("2d");this.image=Runner.imageSprite;this.spritePos=spritePos;this.x=0;this.y=5;this.currentDistance=0;this.maxScore=0;this.highScore=0;this.container=null;this.digits=[];this.achievement=false;this.defaultString="";this.flashTimer=0;this.flashIterations=0;this.invertTrigger=false;this.flashingRafId=null;this.highScoreBounds={};this.highScoreFlashing=false;this.config=DistanceMeter.config;this.maxScoreUnits=this.config.MAX_DISTANCE_UNITS;this.init(canvasWidth)}DistanceMeter.dimensions={WIDTH:10,HEIGHT:13,DEST_WIDTH:11};DistanceMeter.yPos=[0,13,27,40,53,67,80,93,107,120];DistanceMeter.config={MAX_DISTANCE_UNITS:5,ACHIEVEMENT_DISTANCE:100,COEFFICIENT:.025,FLASH_DURATION:1e3/4,FLASH_ITERATIONS:3,HIGH_SCORE_HIT_AREA_PADDING:4};DistanceMeter.prototype={init:function(width){var maxDistanceStr="";this.calcXPos(width);this.maxScore=this.maxScoreUnits;for(var i=0;i<this.maxScoreUnits;i++){this.draw(i,0);this.defaultString+="0";maxDistanceStr+="9"}this.maxScore=parseInt(maxDistanceStr)},calcXPos:function(canvasWidth){this.x=canvasWidth-DistanceMeter.dimensions.DEST_WIDTH*(this.maxScoreUnits+1)},draw:function(digitPos,value,opt_highScore){var sourceWidth=DistanceMeter.dimensions.WIDTH;var sourceHeight=DistanceMeter.dimensions.HEIGHT;var sourceX=DistanceMeter.dimensions.WIDTH*value;var sourceY=0;var targetX=digitPos*DistanceMeter.dimensions.DEST_WIDTH;var targetY=this.y;var targetWidth=DistanceMeter.dimensions.WIDTH;var targetHeight=DistanceMeter.dimensions.HEIGHT;if(IS_HIDPI){sourceWidth*=2;sourceHeight*=2;sourceX*=2}sourceX+=this.spritePos.x;sourceY+=this.spritePos.y;this.canvasCtx.save();if(opt_highScore){var highScoreX=this.x-this.maxScoreUnits*2*DistanceMeter.dimensions.WIDTH;this.canvasCtx.translate(highScoreX,this.y)}else{this.canvasCtx.translate(this.x,this.y)}this.canvasCtx.drawImage(this.image,sourceX,sourceY,sourceWidth,sourceHeight,targetX,targetY,targetWidth,targetHeight);this.canvasCtx.restore()},getActualDistance:function(distance){return distance?Math.round(distance*this.config.COEFFICIENT):0},update:function(deltaTime,distance){var paint=true;var playSound=false;if(!this.achievement){distance=this.getActualDistance(distance);if(distance>this.maxScore&&this.maxScoreUnits==this.config.MAX_DISTANCE_UNITS){this.maxScoreUnits++;this.maxScore=parseInt(this.maxScore+"9")}else{this.distance=0}if(distance>0){if(distance%this.config.ACHIEVEMENT_DISTANCE==0){this.achievement=true;this.flashTimer=0;playSound=true}var distanceStr=(this.defaultString+distance).substr(-this.maxScoreUnits);this.digits=distanceStr.split("")}else{this.digits=this.defaultString.split("")}}else{if(this.flashIterations<=this.config.FLASH_ITERATIONS){this.flashTimer+=deltaTime;if(this.flashTimer<this.config.FLASH_DURATION){paint=false}else if(this.flashTimer>this.config.FLASH_DURATION*2){this.flashTimer=0;this.flashIterations++}}else{this.achievement=false;this.flashIterations=0;this.flashTimer=0}}if(paint){for(var i=this.digits.length-1;i>=0;i--){this.draw(i,parseInt(this.digits[i]))}}this.drawHighScore();return playSound},drawHighScore:function(){this.canvasCtx.save();this.canvasCtx.globalAlpha=.8;for(var i=this.highScore.length-1;i>=0;i--){this.draw(i,parseInt(this.highScore[i],10),true)}this.canvasCtx.restore()},setHighScore:function(distance){distance=this.getActualDistance(distance);var highScoreStr=(this.defaultString+distance).substr(-this.maxScoreUnits);this.highScore=["10","11",""].concat(highScoreStr.split(""))},hasClickedOnHighScore:function(e){var x=0;var y=0;if(e.touches){var canvasBounds=this.canvas.getBoundingClientRect();x=e.touches[0].clientX-canvasBounds.left;y=e.touches[0].clientY-canvasBounds.top}else{x=e.offsetX;y=e.offsetY}this.highScoreBounds=this.getHighScoreBounds();return x>=this.highScoreBounds.x&&x<=this.highScoreBounds.x+this.highScoreBounds.width&&y>=this.highScoreBounds.y&&y<=this.highScoreBounds.y+this.highScoreBounds.height},getHighScoreBounds:function(){return{x:this.x-this.maxScoreUnits*2*DistanceMeter.dimensions.WIDTH-DistanceMeter.config.HIGH_SCORE_HIT_AREA_PADDING,y:this.y,width:DistanceMeter.dimensions.WIDTH*(this.highScore.length+1)+DistanceMeter.config.HIGH_SCORE_HIT_AREA_PADDING,height:DistanceMeter.dimensions.HEIGHT+DistanceMeter.config.HIGH_SCORE_HIT_AREA_PADDING*2}},flashHighScore:function(){var now=getTimeStamp();var deltaTime=now-(this.frameTimeStamp||now);var paint=true;this.frameTimeStamp=now;if(this.flashIterations>this.config.FLASH_ITERATIONS*2){this.cancelHighScoreFlashing();return}this.flashTimer+=deltaTime;if(this.flashTimer<this.config.FLASH_DURATION){paint=false}else if(this.flashTimer>this.config.FLASH_DURATION*2){this.flashTimer=0;this.flashIterations++}if(paint){this.drawHighScore()}else{this.clearHighScoreBounds()}this.flashingRafId=requestAnimationFrame(this.flashHighScore.bind(this))},clearHighScoreBounds:function(){this.canvasCtx.save();this.canvasCtx.fillStyle="#fff";this.canvasCtx.rect(this.highScoreBounds.x,this.highScoreBounds.y,this.highScoreBounds.width,this.highScoreBounds.height);this.canvasCtx.fill();this.canvasCtx.restore()},startHighScoreFlashing(){this.highScoreFlashing=true;this.flashHighScore()},isHighScoreFlashing(){return this.highScoreFlashing},cancelHighScoreFlashing:function(){cancelAnimationFrame(this.flashingRafId);this.flashIterations=0;this.flashTimer=0;this.highScoreFlashing=false;this.clearHighScoreBounds();this.drawHighScore()},resetHighScore:function(){this.setHighScore(0);this.cancelHighScoreFlashing()},reset:function(){this.update(0);this.achievement=false}};function Cloud(canvas,spritePos,containerWidth){this.canvas=canvas;this.canvasCtx=this.canvas.getContext("2d");this.spritePos=spritePos;this.containerWidth=containerWidth;this.xPos=containerWidth;this.yPos=0;this.remove=false;this.cloudGap=getRandomNum(Cloud.config.MIN_CLOUD_GAP,Cloud.config.MAX_CLOUD_GAP);this.init()}Cloud.config={HEIGHT:14,MAX_CLOUD_GAP:400,MAX_SKY_LEVEL:30,MIN_CLOUD_GAP:100,MIN_SKY_LEVEL:71,WIDTH:46};Cloud.prototype={init:function(){this.yPos=getRandomNum(Cloud.config.MAX_SKY_LEVEL,Cloud.config.MIN_SKY_LEVEL);this.draw()},draw:function(){this.canvasCtx.save();var sourceWidth=Cloud.config.WIDTH;var sourceHeight=Cloud.config.HEIGHT;var outputWidth=sourceWidth;var outputHeight=sourceHeight;if(IS_HIDPI){sourceWidth=sourceWidth*2;sourceHeight=sourceHeight*2}this.canvasCtx.drawImage(Runner.imageSprite,this.spritePos.x,this.spritePos.y,sourceWidth,sourceHeight,this.xPos,this.yPos,outputWidth,outputHeight);this.canvasCtx.restore()},update:function(speed){if(!this.remove){this.xPos-=Math.ceil(speed);this.draw();if(!this.isVisible()){this.remove=true}}},isVisible:function(){return this.xPos+Cloud.config.WIDTH>0}};function NightMode(canvas,spritePos,containerWidth){this.spritePos=spritePos;this.canvas=canvas;this.canvasCtx=canvas.getContext("2d");this.xPos=containerWidth-50;this.yPos=30;this.currentPhase=0;this.opacity=0;this.containerWidth=containerWidth;this.stars=[];this.drawStars=false;this.placeStars()}NightMode.config={FADE_SPEED:.035,HEIGHT:40,MOON_SPEED:.25,NUM_STARS:2,STAR_SIZE:9,STAR_SPEED:.3,STAR_MAX_Y:70,WIDTH:20};NightMode.phases=[140,120,100,60,40,20,0];NightMode.prototype={update:function(activated,delta){if(activated&&this.opacity==0){this.currentPhase++;if(this.currentPhase>=NightMode.phases.length){this.currentPhase=0}}if(activated&&(this.opacity<1||this.opacity==0)){this.opacity+=NightMode.config.FADE_SPEED}else if(this.opacity>0){this.opacity-=NightMode.config.FADE_SPEED}if(this.opacity>0){this.xPos=this.updateXPos(this.xPos,NightMode.config.MOON_SPEED);if(this.drawStars){for(var i=0;i<NightMode.config.NUM_STARS;i++){this.stars[i].x=this.updateXPos(this.stars[i].x,NightMode.config.STAR_SPEED)}}this.draw()}else{this.opacity=0;this.placeStars()}this.drawStars=true},updateXPos:function(currentPos,speed){if(currentPos<-NightMode.config.WIDTH){currentPos=this.containerWidth}else{currentPos-=speed}return currentPos},draw:function(){var moonSourceWidth=this.currentPhase==3?NightMode.config.WIDTH*2:NightMode.config.WIDTH;var moonSourceHeight=NightMode.config.HEIGHT;var moonSourceX=this.spritePos.x+NightMode.phases[this.currentPhase];var moonOutputWidth=moonSourceWidth;var starSize=NightMode.config.STAR_SIZE;var starSourceX=Runner.spriteDefinition.LDPI.STAR.x;if(IS_HIDPI){moonSourceWidth*=2;moonSourceHeight*=2;moonSourceX=this.spritePos.x+NightMode.phases[this.currentPhase]*2;starSize*=2;starSourceX=Runner.spriteDefinition.HDPI.STAR.x}this.canvasCtx.save();this.canvasCtx.globalAlpha=this.opacity;if(this.drawStars){for(var i=0;i<NightMode.config.NUM_STARS;i++){this.canvasCtx.drawImage(Runner.imageSprite,starSourceX,this.stars[i].sourceY,starSize,starSize,Math.round(this.stars[i].x),this.stars[i].y,NightMode.config.STAR_SIZE,NightMode.config.STAR_SIZE)}}this.canvasCtx.drawImage(Runner.imageSprite,moonSourceX,this.spritePos.y,moonSourceWidth,moonSourceHeight,Math.round(this.xPos),this.yPos,moonOutputWidth,NightMode.config.HEIGHT);this.canvasCtx.globalAlpha=1;this.canvasCtx.restore()},placeStars:function(){var segmentSize=Math.round(this.containerWidth/NightMode.config.NUM_STARS);for(var i=0;i<NightMode.config.NUM_STARS;i++){this.stars[i]={};this.stars[i].x=getRandomNum(segmentSize*i,segmentSize*(i+1));this.stars[i].y=getRandomNum(0,NightMode.config.STAR_MAX_Y);if(IS_HIDPI){this.stars[i].sourceY=Runner.spriteDefinition.HDPI.STAR.y+NightMode.config.STAR_SIZE*2*i}else{this.stars[i].sourceY=Runner.spriteDefinition.LDPI.STAR.y+NightMode.config.STAR_SIZE*i}}},reset:function(){this.currentPhase=0;this.opacity=0;this.update(false)}};function HorizonLine(canvas,spritePos){this.spritePos=spritePos;this.canvas=canvas;this.canvasCtx=canvas.getContext("2d");this.sourceDimensions={};this.dimensions=HorizonLine.dimensions;this.sourceXPos=[this.spritePos.x,this.spritePos.x+this.dimensions.WIDTH];this.xPos=[];this.yPos=0;this.bumpThreshold=.5;this.setSourceDimensions();this.draw()}HorizonLine.dimensions={WIDTH:600,HEIGHT:12,YPOS:127};HorizonLine.prototype={setSourceDimensions:function(){for(var dimension in HorizonLine.dimensions){if(IS_HIDPI){if(dimension!="YPOS"){this.sourceDimensions[dimension]=HorizonLine.dimensions[dimension]*2}}else{this.sourceDimensions[dimension]=HorizonLine.dimensions[dimension]}this.dimensions[dimension]=HorizonLine.dimensions[dimension]}this.xPos=[0,HorizonLine.dimensions.WIDTH];this.yPos=HorizonLine.dimensions.YPOS},getRandomType:function(){return Math.random()>this.bumpThreshold?this.dimensions.WIDTH:0},draw:function(){this.canvasCtx.drawImage(Runner.imageSprite,this.sourceXPos[0],this.spritePos.y,this.sourceDimensions.WIDTH,this.sourceDimensions.HEIGHT,this.xPos[0],this.yPos,this.dimensions.WIDTH,this.dimensions.HEIGHT);this.canvasCtx.drawImage(Runner.imageSprite,this.sourceXPos[1],this.spritePos.y,this.sourceDimensions.WIDTH,this.sourceDimensions.HEIGHT,this.xPos[1],this.yPos,this.dimensions.WIDTH,this.dimensions.HEIGHT)},updateXPos:function(pos,increment){var line1=pos;var line2=pos==0?1:0;this.xPos[line1]-=increment;this.xPos[line2]=this.xPos[line1]+this.dimensions.WIDTH;if(this.xPos[line1]<=-this.dimensions.WIDTH){this.xPos[line1]+=this.dimensions.WIDTH*2;this.xPos[line2]=this.xPos[line1]-this.dimensions.WIDTH;this.sourceXPos[line1]=this.getRandomType()+this.spritePos.x}},update:function(deltaTime,speed){var increment=Math.floor(speed*(FPS/1e3)*deltaTime);if(this.xPos[0]<=0){this.updateXPos(0,increment)}else{this.updateXPos(1,increment)}this.draw()},reset:function(){this.xPos[0]=0;this.xPos[1]=HorizonLine.dimensions.WIDTH}};function Horizon(canvas,spritePos,dimensions,gapCoefficient){this.canvas=canvas;this.canvasCtx=this.canvas.getContext("2d");this.config=Horizon.config;this.dimensions=dimensions;this.gapCoefficient=gapCoefficient;this.obstacles=[];this.obstacleHistory=[];this.horizonOffsets=[0,0];this.cloudFrequency=this.config.CLOUD_FREQUENCY;this.spritePos=spritePos;this.nightMode=null;this.clouds=[];this.cloudSpeed=this.config.BG_CLOUD_SPEED;this.horizonLine=null;this.init()}Horizon.config={BG_CLOUD_SPEED:.2,BUMPY_THRESHOLD:.3,CLOUD_FREQUENCY:.5,HORIZON_HEIGHT:16,MAX_CLOUDS:6};Horizon.prototype={init:function(){this.addCloud();this.horizonLine=new HorizonLine(this.canvas,this.spritePos.HORIZON);this.nightMode=new NightMode(this.canvas,this.spritePos.MOON,this.dimensions.WIDTH)},update:function(deltaTime,currentSpeed,updateObstacles,showNightMode){this.runningTime+=deltaTime;this.horizonLine.update(deltaTime,currentSpeed);this.nightMode.update(showNightMode);this.updateClouds(deltaTime,currentSpeed);if(updateObstacles){this.updateObstacles(deltaTime,currentSpeed)}},updateClouds:function(deltaTime,speed){var cloudSpeed=this.cloudSpeed/1e3*deltaTime*speed;var numClouds=this.clouds.length;if(numClouds){for(var i=numClouds-1;i>=0;i--){this.clouds[i].update(cloudSpeed)}var lastCloud=this.clouds[numClouds-1];if(numClouds<this.config.MAX_CLOUDS&&this.dimensions.WIDTH-lastCloud.xPos>lastCloud.cloudGap&&this.cloudFrequency>Math.random()){this.addCloud()}this.clouds=this.clouds.filter(function(obj){return!obj.remove})}else{this.addCloud()}},updateObstacles:function(deltaTime,currentSpeed){var updatedObstacles=this.obstacles.slice(0);for(var i=0;i<this.obstacles.length;i++){var obstacle=this.obstacles[i];obstacle.update(deltaTime,currentSpeed);if(obstacle.remove){updatedObstacles.shift()}}this.obstacles=updatedObstacles;if(this.obstacles.length>0){var lastObstacle=this.obstacles[this.obstacles.length-1];if(lastObstacle&&!lastObstacle.followingObstacleCreated&&lastObstacle.isVisible()&&lastObstacle.xPos+lastObstacle.width+lastObstacle.gap<this.dimensions.WIDTH){this.addNewObstacle(currentSpeed);lastObstacle.followingObstacleCreated=true}}else{this.addNewObstacle(currentSpeed)}},removeFirstObstacle:function(){this.obstacles.shift()},addNewObstacle:function(currentSpeed){var obstacleTypeIndex=getRandomNum(0,Obstacle.types.length-1);var obstacleType=Obstacle.types[obstacleTypeIndex];if(this.duplicateObstacleCheck(obstacleType.type)||currentSpeed<obstacleType.minSpeed){this.addNewObstacle(currentSpeed)}else{var obstacleSpritePos=this.spritePos[obstacleType.type];this.obstacles.push(new Obstacle(this.canvasCtx,obstacleType,obstacleSpritePos,this.dimensions,this.gapCoefficient,currentSpeed,obstacleType.width));this.obstacleHistory.unshift(obstacleType.type);if(this.obstacleHistory.length>1){this.obstacleHistory.splice(Runner.config.MAX_OBSTACLE_DUPLICATION)}}},duplicateObstacleCheck:function(nextObstacleType){var duplicateCount=0;for(var i=0;i<this.obstacleHistory.length;i++){duplicateCount=this.obstacleHistory[i]==nextObstacleType?duplicateCount+1:0}return duplicateCount>=Runner.config.MAX_OBSTACLE_DUPLICATION},reset:function(){this.obstacles=[];this.horizonLine.reset();this.nightMode.reset()},resize:function(width,height){this.canvas.width=width;this.canvas.height=height},addCloud:function(){this.clouds.push(new Cloud(this.canvas,this.spritePos.CLOUD,this.dimensions.WIDTH))}}})();</script>
<script>new Runner('#main-frame-error');</script>
\ No newline at end of file
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
const express = require('express') const express = require('express')
var https = require('https') var https = require('https')
const auth = require('basic-auth') const auth = require('basic-auth')
const app = express()
const appHttps = express() const appHttps = express()
const appAuthBasic = express() const appAuthBasic = express()
const fs = require('fs') const fs = require('fs')
...@@ -78,6 +79,40 @@ appAuthBasic.get("/", (req, res) => { ...@@ -78,6 +79,40 @@ appAuthBasic.get("/", (req, res) => {
</body> </body>
</html> </html>
`); `);
res.end()
}) })
appAuthBasic.listen(8081) appAuthBasic.listen(8081)
\ No newline at end of file
// Parse URL-encoded bodies (as sent by HTML forms)
app.use(express.urlencoded());
// Parse JSON bodies (as sent by API clients)
app.use(express.json());
app.get("/", (req, res) => {
res.send(`
<html>
<head>
</head>
<body>
<p>HELLO</p>
</body>
</html>
`);
res.end()
})
app.post("/test-post", (req, res) => {
res.send(`
<html>
<head>
</head>
<body>
<p>HELLO ${req.body.name}!</p>
</body>
</html>
`);
res.end()
})
app.listen(8082)
\ No newline at end of file
...@@ -24,6 +24,9 @@ flutter: ...@@ -24,6 +24,9 @@ flutter:
androidPackage: com.pichillilorenzo.flutter_inappbrowser androidPackage: com.pichillilorenzo.flutter_inappbrowser
pluginClass: InAppBrowserFlutterPlugin pluginClass: InAppBrowserFlutterPlugin
assets:
- packages/flutter_inappbrowser/t_rex_runner/t-rex.html
- packages/flutter_inappbrowser/t_rex_runner/t-rex.css
# To add assets to your plugin package, add an assets section, like this: # To add assets to your plugin package, add an assets section, like this:
# assets: # assets:
# - images/a_dot_burr.jpeg # - images/a_dot_burr.jpeg
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment