diff --git a/CHANGELOG.md b/CHANGELOG.md index fc405027..0239247d 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ ## 6.0.0-beta.24 - Added InAppWebView keep alive feature +- Added InAppBrowser menu items feature - Added `hasJavaScriptHandler`, `hasUserScript`, `hasWebMessageListener` InAppWebViewController methods +- Added `hideCloseButton`, `hideDefaultMenuItems`, `menuButtonColor` InAppBrowser settings - `HeadlessInAppWebView.webViewController` could be `null` - Removed `throwIfAlreadyOpened`, `throwIfNotOpened` InAppBrowser methods - Removed `throwIfAlreadyOpened`, `throwIfNotOpened` ChromeSafariBrowser methods diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/Util.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/Util.java index e9b148c2..e85bb607 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/Util.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/Util.java @@ -2,8 +2,11 @@ package com.pichillilorenzo.flutter_inappwebview; import android.content.Context; import android.content.res.AssetManager; +import android.graphics.BitmapFactory; import android.graphics.Insets; import android.graphics.Rect; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.net.http.SslCertificate; import android.os.Build; import android.os.Bundle; @@ -379,4 +382,8 @@ public class Util { } return null; } + + public static Drawable drawableFromBytes(Context context, byte[] data) { + return new BitmapDrawable(context.getResources(), BitmapFactory.decodeByteArray(data, 0, data.length)); + } } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserActivity.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserActivity.java index efe8a7ad..9f9c5aea 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserActivity.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserActivity.java @@ -1,5 +1,6 @@ package com.pichillilorenzo.flutter_inappwebview.in_app_browser; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; import android.graphics.Color; @@ -18,9 +19,11 @@ import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.SearchView; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.view.menu.MenuBuilder; import com.pichillilorenzo.flutter_inappwebview.R; import com.pichillilorenzo.flutter_inappwebview.Util; @@ -28,7 +31,9 @@ import com.pichillilorenzo.flutter_inappwebview.find_interaction.FindInteraction import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshChannelDelegate; import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshLayout; import com.pichillilorenzo.flutter_inappwebview.pull_to_refresh.PullToRefreshSettings; +import com.pichillilorenzo.flutter_inappwebview.types.AndroidResource; import com.pichillilorenzo.flutter_inappwebview.types.Disposable; +import com.pichillilorenzo.flutter_inappwebview.types.InAppBrowserMenuItem; import com.pichillilorenzo.flutter_inappwebview.types.URLRequest; import com.pichillilorenzo.flutter_inappwebview.types.UserScript; import com.pichillilorenzo.flutter_inappwebview.webview.WebViewChannelDelegate; @@ -71,6 +76,7 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow public InAppBrowserManager manager; @Nullable public InAppBrowserChannelDelegate channelDelegate; + public List menuItems = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { @@ -119,6 +125,10 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow Map contextMenu = (Map) b.getSerializable("contextMenu"); List> initialUserScripts = (List>) b.getSerializable("initialUserScripts"); + List> menuItemList = (List>) b.getSerializable("menuItems"); + for (Map menuItem : menuItemList) { + menuItems.add(InAppBrowserMenuItem.fromMap(menuItem)); + } InAppWebViewSettings webViewSettings = new InAppWebViewSettings(); webViewSettings.parse(settingsMap); @@ -191,10 +201,12 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow progressBar = findViewById(R.id.progressBar); - if (customSettings.hideProgressBar) - progressBar.setMax(0); - else - progressBar.setMax(100); + if (progressBar != null) { + if (customSettings.hideProgressBar) + progressBar.setMax(0); + else + progressBar.setMax(100); + } if (actionBar != null) { actionBar.setDisplayShowTitleEnabled(!customSettings.hideTitleBar); @@ -210,6 +222,7 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow } } + @SuppressLint("RestrictedApi") @Override public boolean onCreateOptionsMenu(Menu m) { menu = m; @@ -220,16 +233,20 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow if (menu == null) return super.onCreateOptionsMenu(m); + if (menu instanceof MenuBuilder) { + ((MenuBuilder) menu).setOptionalIconsVisible(true); + } + MenuInflater inflater = getMenuInflater(); // Inflate menu to add items to action bar if it is present. inflater.inflate(R.menu.menu_main, menu); - MenuItem menuItem = menu.findItem(R.id.menu_search); - if (menuItem != null) { + MenuItem menuSearchItem = menu.findItem(R.id.menu_search); + if (menuSearchItem != null) { if (customSettings.hideUrlBar) - menuItem.setVisible(false); + menuSearchItem.setVisible(false); - searchView = (SearchView) menuItem.getActionView(); + searchView = (SearchView) menuSearchItem.getActionView(); if (searchView != null) { searchView.setFocusable(true); @@ -278,6 +295,58 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow } } + if (customSettings.hideDefaultMenuItems) { + MenuItem actionClose = menu.findItem(R.id.action_close); + if (actionClose != null) { + actionClose.setVisible(false); + } + MenuItem actionGoBack = menu.findItem(R.id.action_go_back); + if (actionGoBack != null) { + actionGoBack.setVisible(false); + } + MenuItem actionReload = menu.findItem(R.id.action_reload); + if (actionReload != null) { + actionReload.setVisible(false); + } + MenuItem actionGoForward = menu.findItem(R.id.action_go_forward); + if (actionGoForward != null) { + actionGoForward.setVisible(false); + } + MenuItem actionShare = menu.findItem(R.id.action_share); + if (actionShare != null) { + actionShare.setVisible(false); + } + } + + for (final InAppBrowserMenuItem menuItem : menuItems) { + int order = menuItem.getOrder() != null ? menuItem.getOrder() : Menu.NONE; + MenuItem item = menu.add(Menu.NONE, menuItem.getId(), order, menuItem.getTitle()); + if (menuItem.isShowAsAction()) { + item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + } + Object icon = menuItem.getIcon(); + if (icon != null) { + if (icon instanceof AndroidResource) { + item.setIcon(((AndroidResource) icon).getIdentifier(this)); + } else { + item.setIcon(Util.drawableFromBytes(this, (byte[]) icon)); + } + String iconColor = menuItem.getIconColor(); + if (iconColor != null && !iconColor.isEmpty() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + item.getIcon().setTint(Color.parseColor(iconColor)); + } + } + item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(@NonNull MenuItem item) { + if (channelDelegate != null) { + channelDelegate.onMenuItemClicked(menuItem); + } + return true; + } + }); + } + return true; } @@ -427,10 +496,33 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow actionBar.setTitle(newSettings.toolbarTopFixedTitle); if (menu != null && newSettingsMap.get("hideUrlBar") != null && customSettings.hideUrlBar != newSettings.hideUrlBar) { - if (newSettings.hideUrlBar) - menu.findItem(R.id.menu_search).setVisible(false); - else - menu.findItem(R.id.menu_search).setVisible(true); + MenuItem menuSearchItem = menu.findItem(R.id.menu_search); + if (menuSearchItem != null) { + menuSearchItem.setVisible(!newSettings.hideUrlBar); + } + } + + if (menu != null && newSettingsMap.get("hideDefaultMenuItems") != null && customSettings.hideDefaultMenuItems != newSettings.hideDefaultMenuItems) { + MenuItem actionClose = menu.findItem(R.id.action_close); + if (actionClose != null) { + actionClose.setVisible(!newSettings.hideDefaultMenuItems); + } + MenuItem actionGoBack = menu.findItem(R.id.action_go_back); + if (actionGoBack != null) { + actionGoBack.setVisible(!newSettings.hideDefaultMenuItems); + } + MenuItem actionReload = menu.findItem(R.id.action_reload); + if (actionReload != null) { + actionReload.setVisible(!newSettings.hideDefaultMenuItems); + } + MenuItem actionGoForward = menu.findItem(R.id.action_go_forward); + if (actionGoForward != null) { + actionGoForward.setVisible(!newSettings.hideDefaultMenuItems); + } + MenuItem actionShare = menu.findItem(R.id.action_share); + if (actionShare != null) { + actionShare.setVisible(!newSettings.hideDefaultMenuItems); + } } customSettings = newSettings; diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserChannelDelegate.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserChannelDelegate.java index 0febcb77..4976d6e6 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserChannelDelegate.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserChannelDelegate.java @@ -3,6 +3,7 @@ package com.pichillilorenzo.flutter_inappwebview.in_app_browser; import androidx.annotation.NonNull; import com.pichillilorenzo.flutter_inappwebview.types.ChannelDelegateImpl; +import com.pichillilorenzo.flutter_inappwebview.types.InAppBrowserMenuItem; import java.util.HashMap; import java.util.Map; @@ -21,6 +22,14 @@ public class InAppBrowserChannelDelegate extends ChannelDelegateImpl { channel.invokeMethod("onBrowserCreated", obj); } + public void onMenuItemClicked(InAppBrowserMenuItem menuItem) { + MethodChannel channel = getChannel(); + if (channel == null) return; + Map obj = new HashMap<>(); + obj.put("id", menuItem.getId()); + channel.invokeMethod("onMenuItemClicked", obj); + } + public void onExit() { MethodChannel channel = getChannel(); if (channel == null) return; diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserManager.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserManager.java index 189ed20d..15985036 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserManager.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserManager.java @@ -181,6 +181,7 @@ public class InAppBrowserManager extends ChannelDelegateImpl { Integer windowId = (Integer) arguments.get("windowId"); List> initialUserScripts = (List>) arguments.get("initialUserScripts"); Map pullToRefreshInitialSettings = (Map) arguments.get("pullToRefreshSettings"); + List> menuItems = (List>) arguments.get("menuItems"); Bundle extras = new Bundle(); extras.putString("fromActivity", activity.getClass().getName()); @@ -198,6 +199,7 @@ public class InAppBrowserManager extends ChannelDelegateImpl { extras.putInt("windowId", windowId != null ? windowId : -1); extras.putSerializable("initialUserScripts", (Serializable) initialUserScripts); extras.putSerializable("pullToRefreshInitialSettings", (Serializable) pullToRefreshInitialSettings); + extras.putSerializable("menuItems", (Serializable) menuItems); startInAppBrowserActivity(activity, extras); } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserSettings.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserSettings.java index 6e720949..c002f4c4 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserSettings.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/in_app_browser/InAppBrowserSettings.java @@ -26,6 +26,7 @@ public class InAppBrowserSettings implements ISettings { public Boolean closeOnCannotGoBack = true; public Boolean allowGoBackWithBackButton = true; public Boolean shouldCloseOnBackButtonPressed = false; + public Boolean hideDefaultMenuItems = false; @NonNull @Override @@ -68,6 +69,9 @@ public class InAppBrowserSettings implements ISettings { case "shouldCloseOnBackButtonPressed": shouldCloseOnBackButtonPressed = (Boolean) value; break; + case "hideDefaultMenuItems": + hideDefaultMenuItems = (Boolean) value; + break; } } @@ -88,6 +92,7 @@ public class InAppBrowserSettings implements ISettings { settings.put("hideProgressBar", hideProgressBar); settings.put("allowGoBackWithBackButton", allowGoBackWithBackButton); settings.put("shouldCloseOnBackButtonPressed", shouldCloseOnBackButtonPressed); + settings.put("hideDefaultMenuItems", hideDefaultMenuItems); return settings; } diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/InAppBrowserMenuItem.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/InAppBrowserMenuItem.java new file mode 100644 index 00000000..b975da11 --- /dev/null +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/types/InAppBrowserMenuItem.java @@ -0,0 +1,146 @@ +package com.pichillilorenzo.flutter_inappwebview.types; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.pichillilorenzo.flutter_inappwebview.Util; + +import java.util.Map; +import java.util.Objects; + +public class InAppBrowserMenuItem { + private int id; + + @NonNull + private String title; + + @Nullable + private Integer order; + + @Nullable + private Object icon; + + @Nullable + private String iconColor; + + private boolean showAsAction; + + public InAppBrowserMenuItem(int id, @NonNull String title, @Nullable Integer order, @Nullable Object icon, + @Nullable String iconColor, boolean showAsAction) { + this.id = id; + this.title = title; + this.order = order; + this.icon = icon; + this.iconColor = iconColor; + this.showAsAction = showAsAction; + } + + @Nullable + public static InAppBrowserMenuItem fromMap(@Nullable Map map) { + if (map == null) { + return null; + } + int id = (int) map.get("id"); + String title = (String) map.get("title"); + Integer order = (Integer) map.get("order"); + Object icon = map.get("icon"); + if (icon instanceof Map) { + icon = AndroidResource.fromMap((Map) map.get("icon")); + } else if (!(icon instanceof byte[])) { + icon = null; + } + String iconColor = (String) map.get("iconColor"); + boolean showAsAction = Util.getOrDefault( map, "showAsAction", false); + return new InAppBrowserMenuItem(id, title, order, icon, iconColor, showAsAction); + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + @NonNull + public String getTitle() { + return title; + } + + public void setTitle(@NonNull String title) { + this.title = title; + } + + @Nullable + public Integer getOrder() { + return order; + } + + public void setOrder(@Nullable Integer order) { + this.order = order; + } + + @Nullable + public Object getIcon() { + return icon; + } + + public void setIcon(@Nullable Object icon) { + this.icon = icon; + } + + @Nullable + public String getIconColor() { + return iconColor; + } + + public void setIconColor(@Nullable String iconColor) { + this.iconColor = iconColor; + } + + public boolean isShowAsAction() { + return showAsAction; + } + + public void setShowAsAction(boolean showAsAction) { + this.showAsAction = showAsAction; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + InAppBrowserMenuItem that = (InAppBrowserMenuItem) o; + + if (id != that.id) return false; + if (showAsAction != that.showAsAction) return false; + if (!title.equals(that.title)) return false; + if (!Objects.equals(order, that.order)) return false; + if (!Objects.equals(icon, that.icon)) return false; + return Objects.equals(iconColor, that.iconColor); + } + + @Override + public int hashCode() { + int result = id; + result = 31 * result + title.hashCode(); + result = 31 * result + (order != null ? order.hashCode() : 0); + result = 31 * result + (icon != null ? icon.hashCode() : 0); + result = 31 * result + (iconColor != null ? iconColor.hashCode() : 0); + result = 31 * result + (showAsAction ? 1 : 0); + return result; + } + + @Override + public String toString() { + return "InAppBrowserMenuItem{" + + "id=" + id + + ", title='" + title + '\'' + + ", order=" + order + + ", icon=" + icon + + ", iconColor='" + iconColor + '\'' + + ", showAsAction=" + showAsAction + + '}'; + } +} diff --git a/dev_packages/generators/lib/src/exchangeable_object_generator.dart b/dev_packages/generators/lib/src/exchangeable_object_generator.dart index 276c2e7d..a076dbf4 100644 --- a/dev_packages/generators/lib/src/exchangeable_object_generator.dart +++ b/dev_packages/generators/lib/src/exchangeable_object_generator.dart @@ -321,7 +321,8 @@ class ExchangeableObjectGenerator final fieldName = fieldElement.name; if (!fieldElement.isPrivate && !fieldElement.isStatic && - !fieldElement.type.isDartCoreFunction) { + !(fieldElement.type.isDartCoreFunction || + fieldElement.type is FunctionType)) { var value = "map['$fieldName']"; final deprecationMessage = _coreCheckerDeprecated .firstAnnotationOfExact(fieldElement) @@ -354,10 +355,10 @@ class ExchangeableObjectGenerator final constructorParameter = visitor.constructorParameters[fieldName]; final isRequiredParameter = constructorParameter != null && (constructorParameter.isRequiredNamed || - constructorParameter.isFinal || + constructorParameter.isFinal || fieldElement.isFinal || !Util.typeIsNullable(constructorParameter.type)) && !constructorParameter.hasDefaultValue; - if (isRequiredParameter) { + if (isRequiredParameter || fieldElement.isFinal) { requiredFields.add('$fieldName: $value,'); } else { nonRequiredFields.add("instance.$fieldName = $value;"); @@ -402,23 +403,14 @@ class ExchangeableObjectGenerator classBuffer.writeln('///Converts instance to a map.'); classBuffer.writeln('Map toMap() {'); classBuffer.writeln('return {'); - for (final entry in methodEntriesSorted) { - final methodElement = entry.value; - final toMapMergeWith = _coreCheckerObjectMethod - .firstAnnotationOf(methodElement) - ?.getField("toMapMergeWith") - ?.toBoolValue(); - if (toMapMergeWith == true) { - classBuffer.writeln('...${methodElement.name}(),'); - } - } final fieldElements = []; if (superClass != null) { for (final fieldElement in superClass.element.fields) { if (!fieldElement.isPrivate && !fieldElement.hasDeprecated && !fieldElement.isStatic && - !fieldElement.type.isDartCoreFunction) { + !(fieldElement.type.isDartCoreFunction || + fieldElement.type is FunctionType)) { fieldElements.add(fieldElement); } } @@ -428,7 +420,8 @@ class ExchangeableObjectGenerator if (!fieldElement.isPrivate && !fieldElement.hasDeprecated && !fieldElement.isStatic && - !fieldElement.type.isDartCoreFunction) { + !(fieldElement.type.isDartCoreFunction || + fieldElement.type is FunctionType)) { fieldElements.add(fieldElement); } } @@ -436,7 +429,8 @@ class ExchangeableObjectGenerator if (!fieldElement.isPrivate && !fieldElement.hasDeprecated && !fieldElement.isStatic && - !fieldElement.type.isDartCoreFunction) { + !(fieldElement.type.isDartCoreFunction || + fieldElement.type is FunctionType)) { final fieldName = fieldElement.name; var mapValue = fieldName; final customSerializer = _coreCheckerObjectProperty @@ -458,6 +452,16 @@ class ExchangeableObjectGenerator classBuffer.writeln('"$fieldName": $mapValue,'); } } + for (final entry in methodEntriesSorted) { + final methodElement = entry.value; + final toMapMergeWith = _coreCheckerObjectMethod + .firstAnnotationOf(methodElement) + ?.getField("toMapMergeWith") + ?.toBoolValue(); + if (toMapMergeWith == true) { + classBuffer.writeln('...${methodElement.name}(),'); + } + } classBuffer.writeln('};'); classBuffer.writeln('}'); } @@ -494,7 +498,8 @@ class ExchangeableObjectGenerator if (!fieldElement.isPrivate && !fieldElement.hasDeprecated && !fieldElement.isStatic && - !fieldElement.type.isDartCoreFunction) { + !(fieldElement.type.isDartCoreFunction || + fieldElement.type is FunctionType)) { fieldNames.add('$fieldName: \$$fieldName'); } } @@ -505,7 +510,8 @@ class ExchangeableObjectGenerator if (!fieldElement.isPrivate && !fieldElement.hasDeprecated && !fieldElement.isStatic && - !fieldElement.type.isDartCoreFunction) { + !(fieldElement.type.isDartCoreFunction || + fieldElement.type is FunctionType)) { fieldNames.add('$fieldName: \$$fieldName'); } } diff --git a/example/integration_test/chrome_safari_browser/custom_menu_item.dart b/example/integration_test/chrome_safari_browser/custom_menu_item.dart index d441f6a5..0f0ae1b5 100644 --- a/example/integration_test/chrome_safari_browser/custom_menu_item.dart +++ b/example/integration_test/chrome_safari_browser/custom_menu_item.dart @@ -1,9 +1,4 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; -import '../util.dart'; +part of 'main.dart'; void customMenuItem() { final shouldSkip = kIsWeb @@ -11,7 +6,7 @@ void customMenuItem() { : ![TargetPlatform.android, TargetPlatform.iOS] .contains(defaultTargetPlatform); - test('add custom menu item', () async { + skippableTest('add custom menu item', () async { var chromeSafariBrowser = MyChromeSafariBrowser(); chromeSafariBrowser.addMenuItem(ChromeSafariBrowserMenuItem( id: 2, @@ -25,7 +20,7 @@ void customMenuItem() { expect(chromeSafariBrowser.isOpened(), true); expect(() async { await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1); - }, throwsException); + }, throwsAssertionError); await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes); await chromeSafariBrowser.close(); diff --git a/example/integration_test/chrome_safari_browser/custom_tabs.dart b/example/integration_test/chrome_safari_browser/custom_tabs.dart index ca76f9b5..80b64d3d 100644 --- a/example/integration_test/chrome_safari_browser/custom_tabs.dart +++ b/example/integration_test/chrome_safari_browser/custom_tabs.dart @@ -1,10 +1,4 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; -import '../util.dart'; +part of 'main.dart'; void customTabs() { final shouldSkip = kIsWeb @@ -13,8 +7,8 @@ void customTabs() { TargetPlatform.android, ].contains(defaultTargetPlatform); - group('Custom Tabs', () { - test('custom referrer', () async { + skippableGroup('Custom Tabs', () { + skippableTest('custom referrer', () async { var chromeSafariBrowser = MyChromeSafariBrowser(); expect(chromeSafariBrowser.isOpened(), false); @@ -26,7 +20,7 @@ void customTabs() { expect(chromeSafariBrowser.isOpened(), true); expect(() async { await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1); - }, throwsException); + }, throwsAssertionError); await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes); await chromeSafariBrowser.close(); @@ -34,7 +28,7 @@ void customTabs() { expect(chromeSafariBrowser.isOpened(), false); }); - test('single instance', () async { + skippableTest('single instance', () async { var chromeSafariBrowser = MyChromeSafariBrowser(); expect(chromeSafariBrowser.isOpened(), false); @@ -45,7 +39,7 @@ void customTabs() { expect(chromeSafariBrowser.isOpened(), true); expect(() async { await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1); - }, throwsException); + }, throwsAssertionError); await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes); await chromeSafariBrowser.close(); @@ -53,7 +47,7 @@ void customTabs() { expect(chromeSafariBrowser.isOpened(), false); }); - test('add custom action button and update icon', () async { + skippableTest('add custom action button and update icon', () async { var chromeSafariBrowser = MyChromeSafariBrowser(); var actionButtonIcon = await rootBundle.load('test_assets/images/flutter-logo.png'); @@ -71,7 +65,7 @@ void customTabs() { expect(chromeSafariBrowser.isOpened(), true); expect(() async { await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1); - }, throwsException); + }, throwsAssertionError); await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes); await chromeSafariBrowser.updateActionButton( @@ -82,7 +76,7 @@ void customTabs() { expect(chromeSafariBrowser.isOpened(), false); }, skip: shouldSkip); - test('mayLaunchUrl and launchUrl', () async { + skippableTest('mayLaunchUrl and launchUrl', () async { var chromeSafariBrowser = MyChromeSafariBrowser(); expect(chromeSafariBrowser.isOpened(), false); @@ -104,7 +98,7 @@ void customTabs() { expect(chromeSafariBrowser.isOpened(), false); }); - test('onNavigationEvent', () async { + skippableTest('onNavigationEvent', () async { var chromeSafariBrowser = MyChromeSafariBrowser(); expect(chromeSafariBrowser.isOpened(), false); @@ -118,7 +112,7 @@ void customTabs() { expect(chromeSafariBrowser.isOpened(), false); }); - test('add and update secondary toolbar', () async { + skippableTest('add and update secondary toolbar', () async { var chromeSafariBrowser = MyChromeSafariBrowser(); chromeSafariBrowser.setSecondaryToolbar( ChromeSafariBrowserSecondaryToolbar( @@ -172,7 +166,7 @@ void customTabs() { expect(chromeSafariBrowser.isOpened(), false); }); - test('getMaxToolbarItems', () async { + skippableTest('getMaxToolbarItems', () async { expect(await ChromeSafariBrowser.getMaxToolbarItems(), greaterThanOrEqualTo(0)); }); diff --git a/example/integration_test/chrome_safari_browser/main.dart b/example/integration_test/chrome_safari_browser/main.dart index b6a99420..b4ca3d20 100644 --- a/example/integration_test/chrome_safari_browser/main.dart +++ b/example/integration_test/chrome_safari_browser/main.dart @@ -1,17 +1,21 @@ import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../constants.dart'; +import '../util.dart'; -import 'custom_menu_item.dart'; -import 'custom_tabs.dart'; -import 'open_and_close.dart'; -import 'trusted_web_activity.dart'; -import 'sf_safari_view_controller.dart'; +part 'custom_menu_item.dart'; +part 'custom_tabs.dart'; +part 'open_and_close.dart'; +part 'trusted_web_activity.dart'; +part 'sf_safari_view_controller.dart'; void main() { final shouldSkip = kIsWeb || [TargetPlatform.macOS].contains(defaultTargetPlatform); - group('ChromeSafariBrowser', () { + skippableGroup('ChromeSafariBrowser', () { openAndClose(); customMenuItem(); customTabs(); diff --git a/example/integration_test/chrome_safari_browser/open_and_close.dart b/example/integration_test/chrome_safari_browser/open_and_close.dart index 96e99a19..4439e21e 100644 --- a/example/integration_test/chrome_safari_browser/open_and_close.dart +++ b/example/integration_test/chrome_safari_browser/open_and_close.dart @@ -1,9 +1,4 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; -import '../util.dart'; +part of 'main.dart'; void openAndClose() { final shouldSkip = kIsWeb @@ -11,7 +6,7 @@ void openAndClose() { : ![TargetPlatform.android, TargetPlatform.iOS] .contains(defaultTargetPlatform); - test('open and close', () async { + skippableTest('open and close', () async { var chromeSafariBrowser = MyChromeSafariBrowser(); expect(chromeSafariBrowser.isOpened(), false); @@ -50,7 +45,7 @@ void openAndClose() { expect(chromeSafariBrowser.isOpened(), true); expect(() async { await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1); - }, throwsException); + }, throwsAssertionError); await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes); await chromeSafariBrowser.close(); diff --git a/example/integration_test/chrome_safari_browser/sf_safari_view_controller.dart b/example/integration_test/chrome_safari_browser/sf_safari_view_controller.dart index a3e19efd..c4579d67 100644 --- a/example/integration_test/chrome_safari_browser/sf_safari_view_controller.dart +++ b/example/integration_test/chrome_safari_browser/sf_safari_view_controller.dart @@ -1,9 +1,4 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; -import '../util.dart'; +part of 'main.dart'; void sfSafariViewController() { final shouldSkip = kIsWeb @@ -12,8 +7,8 @@ void sfSafariViewController() { TargetPlatform.iOS, ].contains(defaultTargetPlatform); - group('SF Safari View Controller', () { - test('onCompletedInitialLoad did load successfully', () async { + skippableGroup('SF Safari View Controller', () { + skippableTest('onCompletedInitialLoad did load successfully', () async { var chromeSafariBrowser = MyChromeSafariBrowser(); expect(chromeSafariBrowser.isOpened(), false); @@ -22,7 +17,7 @@ void sfSafariViewController() { expect(chromeSafariBrowser.isOpened(), true); expect(() async { await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1); - }, throwsException); + }, throwsAssertionError); expect(await chromeSafariBrowser.firstPageLoaded.future, true); await chromeSafariBrowser.close(); @@ -31,11 +26,11 @@ void sfSafariViewController() { }); // TODO: this test takes a lot of time to complete. Tested on iOS 16.0. - // test('clearWebsiteData', () async { + // skippableTest('clearWebsiteData', () async { // await expectLater(ChromeSafariBrowser.clearWebsiteData(), completes); // }); - test('create and invalidate Prewarming Token', () async { + skippableTest('create and invalidate Prewarming Token', () async { final prewarmingToken = await ChromeSafariBrowser.prewarmConnections([TEST_URL_1]); expect(prewarmingToken, isNotNull); diff --git a/example/integration_test/chrome_safari_browser/trusted_web_activity.dart b/example/integration_test/chrome_safari_browser/trusted_web_activity.dart index a7996dea..8e5844f7 100644 --- a/example/integration_test/chrome_safari_browser/trusted_web_activity.dart +++ b/example/integration_test/chrome_safari_browser/trusted_web_activity.dart @@ -1,9 +1,4 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; -import '../util.dart'; +part of 'main.dart'; void trustedWebActivity() { final shouldSkip = kIsWeb @@ -12,8 +7,8 @@ void trustedWebActivity() { TargetPlatform.android, ].contains(defaultTargetPlatform); - group('Trusted Web Activity', () { - test('basic', () async { + skippableGroup('Trusted Web Activity', () { + skippableTest('basic', () async { var chromeSafariBrowser = MyChromeSafariBrowser(); expect(chromeSafariBrowser.isOpened(), false); @@ -24,7 +19,7 @@ void trustedWebActivity() { expect(chromeSafariBrowser.isOpened(), true); expect(() async { await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1); - }, throwsException); + }, throwsAssertionError); await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes); await chromeSafariBrowser.close(); @@ -32,7 +27,7 @@ void trustedWebActivity() { expect(chromeSafariBrowser.isOpened(), false); }); - test('single instance', () async { + skippableTest('single instance', () async { var chromeSafariBrowser = MyChromeSafariBrowser(); expect(chromeSafariBrowser.isOpened(), false); @@ -44,7 +39,7 @@ void trustedWebActivity() { expect(chromeSafariBrowser.isOpened(), true); expect(() async { await chromeSafariBrowser.open(url: TEST_CROSS_PLATFORM_URL_1); - }, throwsException); + }, throwsAssertionError); await expectLater(chromeSafariBrowser.firstPageLoaded.future, completes); await chromeSafariBrowser.close(); @@ -52,7 +47,7 @@ void trustedWebActivity() { expect(chromeSafariBrowser.isOpened(), false); }); - test('validate relationship', () async { + skippableTest('validate relationship', () async { var chromeSafariBrowser = MyChromeSafariBrowser(); expect(chromeSafariBrowser.isOpened(), false); diff --git a/example/integration_test/cookie_manager/main.dart b/example/integration_test/cookie_manager/main.dart index 5dfa3b64..8e686e84 100644 --- a/example/integration_test/cookie_manager/main.dart +++ b/example/integration_test/cookie_manager/main.dart @@ -1,12 +1,18 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_test/flutter_test.dart'; +import 'dart:async'; -import 'set_get_delete.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; +import 'package:flutter_test/flutter_test.dart'; +import '../constants.dart'; +import '../util.dart'; + +part 'set_get_delete.dart'; void main() { final shouldSkip = kIsWeb; - group('Cookie Manager', () { + skippableGroup('Cookie Manager', () { setGetDelete(); }, skip: shouldSkip); } diff --git a/example/integration_test/cookie_manager/set_get_delete.dart b/example/integration_test/cookie_manager/set_get_delete.dart index 21256d55..be507f41 100644 --- a/example/integration_test/cookie_manager/set_get_delete.dart +++ b/example/integration_test/cookie_manager/set_get_delete.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void setGetDelete() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void setGetDelete() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('set, get, delete', (WidgetTester tester) async { + skippableTestWidgets('set, get, delete', (WidgetTester tester) async { CookieManager cookieManager = CookieManager.instance(); final Completer controllerCompleter = Completer(); diff --git a/example/integration_test/find_interaction_controller/find_interactions.dart b/example/integration_test/find_interaction_controller/find_interactions.dart index 3e98fa20..e7478e62 100644 --- a/example/integration_test/find_interaction_controller/find_interactions.dart +++ b/example/integration_test/find_interaction_controller/find_interactions.dart @@ -1,9 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; +part of 'main.dart'; void findInteractions() { final shouldSkip = kIsWeb @@ -14,7 +9,7 @@ void findInteractions() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('find interactions', (WidgetTester tester) async { + skippableTestWidgets('find interactions', (WidgetTester tester) async { final Completer pageLoaded = Completer(); final findInteractionController = FindInteractionController(); @@ -71,7 +66,7 @@ void findInteractions() { } }, skip: shouldSkip); - testWidgets('onFindResultReceived', (WidgetTester tester) async { + skippableTestWidgets('onFindResultReceived', (WidgetTester tester) async { final Completer pageLoaded = Completer(); final Completer numberOfMatchesCompleter = Completer(); final findInteractionController = FindInteractionController( diff --git a/example/integration_test/find_interaction_controller/main.dart b/example/integration_test/find_interaction_controller/main.dart index 3ba56d80..25a58446 100644 --- a/example/integration_test/find_interaction_controller/main.dart +++ b/example/integration_test/find_interaction_controller/main.dart @@ -1,13 +1,18 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_test/flutter_test.dart'; +import 'dart:async'; -import 'find_interactions.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; +import 'package:flutter_test/flutter_test.dart'; +import '../util.dart'; + +part 'find_interactions.dart'; void main() { final shouldSkip = kIsWeb || [TargetPlatform.macOS].contains(defaultTargetPlatform); - group('FindInteractionController', () { + skippableGroup('FindInteractionController', () { findInteractions(); }, skip: shouldSkip); } diff --git a/example/integration_test/headless_in_app_webview/convert_to_inappwebview.dart b/example/integration_test/headless_in_app_webview/convert_to_inappwebview.dart index 53d36875..e553e7c4 100644 --- a/example/integration_test/headless_in_app_webview/convert_to_inappwebview.dart +++ b/example/integration_test/headless_in_app_webview/convert_to_inappwebview.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void convertToInAppWebView() { final shouldSkip = kIsWeb @@ -15,7 +8,7 @@ void convertToInAppWebView() { TargetPlatform.iOS, ].contains(defaultTargetPlatform); - testWidgets('convert to InAppWebView', (WidgetTester tester) async { + skippableTestWidgets('convert to InAppWebView', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/headless_in_app_webview/custom_size.dart b/example/integration_test/headless_in_app_webview/custom_size.dart index 6fcb94cb..2147408d 100644 --- a/example/integration_test/headless_in_app_webview/custom_size.dart +++ b/example/integration_test/headless_in_app_webview/custom_size.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void customSize() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void customSize() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - test('set and get custom size', () async { + skippableTest('set and get custom size', () async { final Completer controllerCompleter = Completer(); diff --git a/example/integration_test/headless_in_app_webview/main.dart b/example/integration_test/headless_in_app_webview/main.dart index 02e4b22e..7f3bfe9e 100644 --- a/example/integration_test/headless_in_app_webview/main.dart +++ b/example/integration_test/headless_in_app_webview/main.dart @@ -1,13 +1,20 @@ -import 'package:flutter_test/flutter_test.dart'; +import 'dart:async'; -import 'convert_to_inappwebview.dart'; -import 'take_screenshot.dart'; -import 'custom_size.dart'; -import 'run_and_dispose.dart'; -import 'set_get_settings.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; +import 'package:flutter_test/flutter_test.dart'; +import '../constants.dart'; +import '../util.dart'; + +part 'convert_to_inappwebview.dart'; +part 'take_screenshot.dart'; +part 'custom_size.dart'; +part 'run_and_dispose.dart'; +part 'set_get_settings.dart'; void main() { - group('HeadlessInAppWebView', () { + skippableGroup('HeadlessInAppWebView', () { runAndDispose(); takeScreenshot(); customSize(); diff --git a/example/integration_test/headless_in_app_webview/run_and_dispose.dart b/example/integration_test/headless_in_app_webview/run_and_dispose.dart index 4ed55581..b491aef3 100644 --- a/example/integration_test/headless_in_app_webview/run_and_dispose.dart +++ b/example/integration_test/headless_in_app_webview/run_and_dispose.dart @@ -1,10 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void runAndDispose() { final shouldSkip = kIsWeb @@ -15,7 +9,7 @@ void runAndDispose() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - test('run and dispose', () async { + skippableTest('run and dispose', () async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/headless_in_app_webview/set_get_settings.dart b/example/integration_test/headless_in_app_webview/set_get_settings.dart index 687a8d2e..07489aff 100644 --- a/example/integration_test/headless_in_app_webview/set_get_settings.dart +++ b/example/integration_test/headless_in_app_webview/set_get_settings.dart @@ -1,10 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void setGetSettings() { final shouldSkip = kIsWeb @@ -15,7 +9,7 @@ void setGetSettings() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - test('set/get settings', () async { + skippableTest('set/get settings', () async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/headless_in_app_webview/take_screenshot.dart b/example/integration_test/headless_in_app_webview/take_screenshot.dart index 1711b18b..5009e47f 100644 --- a/example/integration_test/headless_in_app_webview/take_screenshot.dart +++ b/example/integration_test/headless_in_app_webview/take_screenshot.dart @@ -1,12 +1,4 @@ -import 'dart:async'; -import 'dart:typed_data'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void takeScreenshot() { final shouldSkip = kIsWeb || @@ -16,7 +8,7 @@ void takeScreenshot() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - test('take screenshot', () async { + skippableTest('take screenshot', () async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_browser/custom_menu_items.dart b/example/integration_test/in_app_browser/custom_menu_items.dart new file mode 100644 index 00000000..8a080787 --- /dev/null +++ b/example/integration_test/in_app_browser/custom_menu_items.dart @@ -0,0 +1,70 @@ +part of 'main.dart'; + +void customMenuItems() { + final shouldSkip = kIsWeb + ? true + : ![ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + ].contains(defaultTargetPlatform); + + skippableTest('custom menu items', () async { + var inAppBrowser = new MyInAppBrowser(); + + final data = (await rootBundle.load('test_assets/images/flutter-logo.png')) + .buffer + .asUint8List(); + + inAppBrowser.addMenuItem(InAppBrowserMenuItem( + id: 0, + title: 'Menu Item 0', + iconColor: Colors.black, + order: 0, + onClick: () { + inAppBrowser.webViewController?.reload(); + }, + )); + inAppBrowser.addMenuItem(InAppBrowserMenuItem( + id: 1, + title: 'Menu Item 1', + icon: data, + showAsAction: true, + order: 2, + onClick: () { + inAppBrowser.webViewController?.reload(); + }, + )); + + var icon = null; + if ([ + TargetPlatform.iOS, + TargetPlatform.macOS, + ].contains(defaultTargetPlatform)) { + icon = UIImage(systemName: 'ellipsis.circle'); + } else if (defaultTargetPlatform == TargetPlatform.android) { + icon = + AndroidResource.drawable(name: 'ic_menu_edit', defPackage: 'android'); + } + inAppBrowser.addMenuItem(InAppBrowserMenuItem( + id: 2, + title: 'Menu Item 2', + icon: icon, + iconColor: Colors.red, + showAsAction: true, + order: 1, + onClick: () { + inAppBrowser.webViewController?.reload(); + }, + )); + + await inAppBrowser.openUrlRequest( + urlRequest: URLRequest(url: TEST_URL_1), + settings: InAppBrowserClassSettings( + browserSettings: InAppBrowserSettings(hideDefaultMenuItems: true))); + await inAppBrowser.browserCreated.future; + await inAppBrowser.firstPageLoaded.future; + + await expectLater(inAppBrowser.close(), completes); + }, skip: shouldSkip); +} diff --git a/example/integration_test/in_app_browser/hide_and_show.dart b/example/integration_test/in_app_browser/hide_and_show.dart index 1e1fa155..86e706b0 100644 --- a/example/integration_test/in_app_browser/hide_and_show.dart +++ b/example/integration_test/in_app_browser/hide_and_show.dart @@ -1,9 +1,4 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; -import '../util.dart'; +part of 'main.dart'; void hideAndShow() { final shouldSkip = kIsWeb @@ -14,7 +9,7 @@ void hideAndShow() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - test('hide and show', () async { + skippableTest('hide and show', () async { var inAppBrowser = new MyInAppBrowser(); await inAppBrowser.openUrlRequest( urlRequest: URLRequest(url: TEST_URL_1), @@ -28,5 +23,7 @@ void hideAndShow() { expect(await inAppBrowser.isHidden(), false); await expectLater(inAppBrowser.hide(), completes); expect(await inAppBrowser.isHidden(), true); + + await expectLater(inAppBrowser.close(), completes); }, skip: shouldSkip); } diff --git a/example/integration_test/in_app_browser/main.dart b/example/integration_test/in_app_browser/main.dart index 4b20e930..a1437e6b 100644 --- a/example/integration_test/in_app_browser/main.dart +++ b/example/integration_test/in_app_browser/main.dart @@ -1,20 +1,27 @@ import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../constants.dart'; +import '../util.dart'; -import 'open_data_and_close.dart'; -import 'open_file_and_close.dart'; -import 'open_url_and_close.dart'; -import 'set_get_settings.dart'; -import 'hide_and_show.dart'; +part 'open_data_and_close.dart'; +part 'open_file_and_close.dart'; +part 'open_url_and_close.dart'; +part 'set_get_settings.dart'; +part 'hide_and_show.dart'; +part 'custom_menu_items.dart'; void main() { final shouldSkip = kIsWeb; - group('InAppBrowser', () { + skippableGroup('InAppBrowser', () { openUrlAndClose(); openFileAndClose(); openDataAndClose(); setGetSettings(); hideAndShow(); + customMenuItems(); }, skip: shouldSkip); } diff --git a/example/integration_test/in_app_browser/open_data_and_close.dart b/example/integration_test/in_app_browser/open_data_and_close.dart index 85dbc3d6..985b4d16 100644 --- a/example/integration_test/in_app_browser/open_data_and_close.dart +++ b/example/integration_test/in_app_browser/open_data_and_close.dart @@ -1,9 +1,4 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; -import '../util.dart'; +part of 'main.dart'; void openDataAndClose() { final shouldSkip = kIsWeb @@ -14,12 +9,12 @@ void openDataAndClose() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - test('open data and close', () async { + skippableTest('open data and close', () async { var inAppBrowser = new MyInAppBrowser(); expect(inAppBrowser.isOpened(), false); expect(() async { await inAppBrowser.show(); - }, throwsException); + }, throwsAssertionError); await inAppBrowser.openData( data: """ @@ -46,7 +41,7 @@ void openDataAndClose() { expect(() async { await inAppBrowser.openUrlRequest( urlRequest: URLRequest(url: TEST_URL_1)); - }, throwsException); + }, throwsAssertionError); await inAppBrowser.firstPageLoaded.future; var controller = inAppBrowser.webViewController; @@ -56,6 +51,7 @@ void openDataAndClose() { expect(url, TEST_CROSS_PLATFORM_URL_1.toString()); await inAppBrowser.close(); + await inAppBrowser.browserClosed.future; expect(inAppBrowser.isOpened(), false); expect(inAppBrowser.webViewController, isNull); }, skip: shouldSkip); diff --git a/example/integration_test/in_app_browser/open_file_and_close.dart b/example/integration_test/in_app_browser/open_file_and_close.dart index 11503383..b1722b25 100644 --- a/example/integration_test/in_app_browser/open_file_and_close.dart +++ b/example/integration_test/in_app_browser/open_file_and_close.dart @@ -1,9 +1,4 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; -import '../util.dart'; +part of 'main.dart'; void openFileAndClose() { final shouldSkip = kIsWeb @@ -14,12 +9,12 @@ void openFileAndClose() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - test('open file and close', () async { + skippableTest('open file and close', () async { var inAppBrowser = new MyInAppBrowser(); expect(inAppBrowser.isOpened(), false); expect(() async { await inAppBrowser.show(); - }, throwsException); + }, throwsAssertionError); await inAppBrowser.openFile( assetFilePath: "test_assets/in_app_webview_initial_file_test.html"); @@ -28,7 +23,7 @@ void openFileAndClose() { expect(() async { await inAppBrowser.openUrlRequest( urlRequest: URLRequest(url: TEST_URL_1)); - }, throwsException); + }, throwsAssertionError); await inAppBrowser.firstPageLoaded.future; var controller = inAppBrowser.webViewController; @@ -38,6 +33,7 @@ void openFileAndClose() { expect(url, endsWith("in_app_webview_initial_file_test.html")); await inAppBrowser.close(); + await inAppBrowser.browserClosed.future; expect(inAppBrowser.isOpened(), false); expect(inAppBrowser.webViewController, isNull); }, skip: shouldSkip); diff --git a/example/integration_test/in_app_browser/open_url_and_close.dart b/example/integration_test/in_app_browser/open_url_and_close.dart index efffc6e7..0d099529 100644 --- a/example/integration_test/in_app_browser/open_url_and_close.dart +++ b/example/integration_test/in_app_browser/open_url_and_close.dart @@ -1,9 +1,4 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; -import '../util.dart'; +part of 'main.dart'; void openUrlAndClose() { final shouldSkip = kIsWeb @@ -14,12 +9,12 @@ void openUrlAndClose() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - test('open url and close', () async { + skippableTest('open url and close', () async { var inAppBrowser = new MyInAppBrowser(); expect(inAppBrowser.isOpened(), false); expect(() async { await inAppBrowser.show(); - }, throwsException); + }, throwsAssertionError); await inAppBrowser.openUrlRequest(urlRequest: URLRequest(url: TEST_URL_1)); await inAppBrowser.browserCreated.future; @@ -27,7 +22,7 @@ void openUrlAndClose() { expect(() async { await inAppBrowser.openUrlRequest( urlRequest: URLRequest(url: TEST_CROSS_PLATFORM_URL_1)); - }, throwsException); + }, throwsAssertionError); await inAppBrowser.firstPageLoaded.future; var controller = inAppBrowser.webViewController; @@ -37,6 +32,7 @@ void openUrlAndClose() { expect(url, TEST_URL_1.toString()); await inAppBrowser.close(); + await inAppBrowser.browserClosed.future; expect(inAppBrowser.isOpened(), false); expect(inAppBrowser.webViewController, isNull); }, skip: shouldSkip); diff --git a/example/integration_test/in_app_browser/set_get_settings.dart b/example/integration_test/in_app_browser/set_get_settings.dart index 82c824a3..5bb7698c 100644 --- a/example/integration_test/in_app_browser/set_get_settings.dart +++ b/example/integration_test/in_app_browser/set_get_settings.dart @@ -1,9 +1,4 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; -import '../util.dart'; +part of 'main.dart'; void setGetSettings() { final shouldSkip = kIsWeb @@ -14,7 +9,7 @@ void setGetSettings() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - test('set/get settings', () async { + skippableTest('set/get settings', () async { var inAppBrowser = new MyInAppBrowser(); await inAppBrowser.openUrlRequest( urlRequest: URLRequest(url: TEST_URL_1), @@ -34,5 +29,7 @@ void setGetSettings() { settings = await inAppBrowser.getSettings(); expect(settings, isNotNull); expect(settings!.browserSettings.hideToolbarTop, false); + + await expectLater(inAppBrowser.close(), completes); }, skip: shouldSkip); } diff --git a/example/integration_test/in_app_localhost_server/load_asset_file.dart b/example/integration_test/in_app_localhost_server/load_asset_file.dart index 08faa9e3..8b84625f 100644 --- a/example/integration_test/in_app_localhost_server/load_asset_file.dart +++ b/example/integration_test/in_app_localhost_server/load_asset_file.dart @@ -1,9 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; +part of 'main.dart'; void loadAssetFile(InAppLocalhostServer localhostServer) { final shouldSkip = kIsWeb @@ -14,7 +9,7 @@ void loadAssetFile(InAppLocalhostServer localhostServer) { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('load asset file', (WidgetTester tester) async { + skippableTestWidgets('load asset file', (WidgetTester tester) async { expect(localhostServer.isRunning(), true); final Completer controllerCompleter = diff --git a/example/integration_test/in_app_localhost_server/main.dart b/example/integration_test/in_app_localhost_server/main.dart index 9d546b63..05bfd21e 100644 --- a/example/integration_test/in_app_localhost_server/main.dart +++ b/example/integration_test/in_app_localhost_server/main.dart @@ -1,13 +1,17 @@ +import 'dart:async'; + import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../util.dart'; -import 'load_asset_file.dart'; +part 'load_asset_file.dart'; void main() { final shouldSkip = kIsWeb; - group('InAppLocalhostServer', () { + skippableGroup('InAppLocalhostServer', () { final InAppLocalhostServer localhostServer = InAppLocalhostServer(); setUpAll(() async { diff --git a/example/integration_test/in_app_webview/apple_pay_api.dart b/example/integration_test/in_app_webview/apple_pay_api.dart index 4734a7b4..e83423a8 100644 --- a/example/integration_test/in_app_webview/apple_pay_api.dart +++ b/example/integration_test/in_app_webview/apple_pay_api.dart @@ -1,9 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; +part of 'main.dart'; void applePayAPI() { final shouldSkip = kIsWeb @@ -13,7 +8,7 @@ void applePayAPI() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('Apple Pay API enabled', (WidgetTester tester) async { + skippableTestWidgets('Apple Pay API enabled', (WidgetTester tester) async { final Completer pageLoaded = Completer(); final Completer alertMessageCompleter = Completer(); diff --git a/example/integration_test/in_app_webview/audio_playback_policy.dart b/example/integration_test/in_app_webview/audio_playback_policy.dart index 7b632b6b..0176047d 100644 --- a/example/integration_test/in_app_webview/audio_playback_policy.dart +++ b/example/integration_test/in_app_webview/audio_playback_policy.dart @@ -1,12 +1,4 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:typed_data'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; +part of 'main.dart'; void audioPlaybackPolicy() { final shouldSkip = kIsWeb @@ -17,7 +9,7 @@ void audioPlaybackPolicy() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - group('Audio playback policy', () { + skippableGroup('Audio playback policy', () { String audioTestBase64 = ""; setUpAll(() async { final ByteData audioData = @@ -48,7 +40,7 @@ void audioPlaybackPolicy() { audioTestBase64 = base64Encode(const Utf8Encoder().convert(audioTest)); }); - testWidgets('Auto media playback', (WidgetTester tester) async { + skippableTestWidgets('Auto media playback', (WidgetTester tester) async { Completer controllerCompleter = Completer(); Completer pageStarted = Completer(); diff --git a/example/integration_test/in_app_webview/clear_cache.dart b/example/integration_test/in_app_webview/clear_cache.dart index 8efbcb98..8c4ece5b 100644 --- a/example/integration_test/in_app_webview/clear_cache.dart +++ b/example/integration_test/in_app_webview/clear_cache.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void clearCache() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void clearCache() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('clearCache', (WidgetTester tester) async { + skippableTestWidgets('clearCache', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/clear_client_cert_preferences.dart b/example/integration_test/in_app_webview/clear_client_cert_preferences.dart index 6cdf8144..5d856d3a 100644 --- a/example/integration_test/in_app_webview/clear_client_cert_preferences.dart +++ b/example/integration_test/in_app_webview/clear_client_cert_preferences.dart @@ -1,6 +1,4 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; +part of 'main.dart'; void clearClientCertPreferences() { final shouldSkip = kIsWeb @@ -9,7 +7,7 @@ void clearClientCertPreferences() { TargetPlatform.android, ].contains(defaultTargetPlatform); - test('clearClientCertPreferences', () async { + skippableTest('clearClientCertPreferences', () async { await expectLater( InAppWebViewController.clearClientCertPreferences(), completes); }, skip: shouldSkip); diff --git a/example/integration_test/in_app_webview/clear_focus.dart b/example/integration_test/in_app_webview/clear_focus.dart index a7d3d878..e961bcf3 100644 --- a/example/integration_test/in_app_webview/clear_focus.dart +++ b/example/integration_test/in_app_webview/clear_focus.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void clearFocus() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void clearFocus() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('clearFocus', (WidgetTester tester) async { + skippableTestWidgets('clearFocus', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/clear_ssl_preferences.dart b/example/integration_test/in_app_webview/clear_ssl_preferences.dart index 765a5036..c02c2714 100644 --- a/example/integration_test/in_app_webview/clear_ssl_preferences.dart +++ b/example/integration_test/in_app_webview/clear_ssl_preferences.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void clearSslPreferences() { final shouldSkip = kIsWeb @@ -14,7 +7,7 @@ void clearSslPreferences() { TargetPlatform.android, ].contains(defaultTargetPlatform); - testWidgets('clearSslPreferences', (WidgetTester tester) async { + skippableTestWidgets('clearSslPreferences', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/content_blocker.dart b/example/integration_test/in_app_webview/content_blocker.dart index ea0fb896..03ba8060 100644 --- a/example/integration_test/in_app_webview/content_blocker.dart +++ b/example/integration_test/in_app_webview/content_blocker.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void contentBlocker() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void contentBlocker() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('Content Blocker', (WidgetTester tester) async { + skippableTestWidgets('Content Blocker', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/create_pdf.dart b/example/integration_test/in_app_webview/create_pdf.dart index 9900584e..acf78371 100644 --- a/example/integration_test/in_app_webview/create_pdf.dart +++ b/example/integration_test/in_app_webview/create_pdf.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void createPdf() { final shouldSkip = kIsWeb @@ -15,7 +8,7 @@ void createPdf() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('createPdf', (WidgetTester tester) async { + skippableTestWidgets('createPdf', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/get_certificate.dart b/example/integration_test/in_app_webview/get_certificate.dart index 00e2d8f8..fc43fef6 100644 --- a/example/integration_test/in_app_webview/get_certificate.dart +++ b/example/integration_test/in_app_webview/get_certificate.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void getCertificate() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void getCertificate() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('getCertificate', (WidgetTester tester) async { + skippableTestWidgets('getCertificate', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/get_content_height.dart b/example/integration_test/in_app_webview/get_content_height.dart index 4783ed35..1e1635fc 100644 --- a/example/integration_test/in_app_webview/get_content_height.dart +++ b/example/integration_test/in_app_webview/get_content_height.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void getContentHeight() { final shouldSkip = kIsWeb @@ -18,7 +11,7 @@ void getContentHeight() { var url = !kIsWeb ? TEST_CROSS_PLATFORM_URL_1 : TEST_WEB_PLATFORM_URL_1; - testWidgets('getContentHeight', (WidgetTester tester) async { + skippableTestWidgets('getContentHeight', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/get_current_web_view_package.dart b/example/integration_test/in_app_webview/get_current_web_view_package.dart index 0f99cf30..b4542350 100644 --- a/example/integration_test/in_app_webview/get_current_web_view_package.dart +++ b/example/integration_test/in_app_webview/get_current_web_view_package.dart @@ -1,6 +1,4 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; +part of 'main.dart'; void getCurrentWebViewPackage() { final shouldSkip = kIsWeb @@ -9,7 +7,7 @@ void getCurrentWebViewPackage() { TargetPlatform.android, ].contains(defaultTargetPlatform); - test('getCurrentWebViewPackage', () async { + skippableTest('getCurrentWebViewPackage', () async { expect(await InAppWebViewController.getCurrentWebViewPackage(), isNotNull); }, skip: shouldSkip); } diff --git a/example/integration_test/in_app_webview/get_default_user_agent.dart b/example/integration_test/in_app_webview/get_default_user_agent.dart index 8d6dfcc7..469699bb 100644 --- a/example/integration_test/in_app_webview/get_default_user_agent.dart +++ b/example/integration_test/in_app_webview/get_default_user_agent.dart @@ -1,6 +1,4 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; +part of 'main.dart'; void getDefaultUserAgent() { final shouldSkip = kIsWeb @@ -11,7 +9,7 @@ void getDefaultUserAgent() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - test('getDefaultUserAgent', () async { + skippableTest('getDefaultUserAgent', () async { expect(await InAppWebViewController.getDefaultUserAgent(), isNotNull); }, skip: shouldSkip); } diff --git a/example/integration_test/in_app_webview/get_favicons.dart b/example/integration_test/in_app_webview/get_favicons.dart index a1e1139a..d2ff44a2 100644 --- a/example/integration_test/in_app_webview/get_favicons.dart +++ b/example/integration_test/in_app_webview/get_favicons.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void getFavicons() { final shouldSkip = kIsWeb @@ -18,7 +11,7 @@ void getFavicons() { var url = !kIsWeb ? TEST_CROSS_PLATFORM_URL_1 : TEST_WEB_PLATFORM_URL_1; - testWidgets('getFavicons', (WidgetTester tester) async { + skippableTestWidgets('getFavicons', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/get_html.dart b/example/integration_test/in_app_webview/get_html.dart index 1ad057ac..a6230478 100644 --- a/example/integration_test/in_app_webview/get_html.dart +++ b/example/integration_test/in_app_webview/get_html.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void getHtml() { final shouldSkip = kIsWeb @@ -18,7 +11,7 @@ void getHtml() { var url = !kIsWeb ? TEST_CROSS_PLATFORM_URL_1 : TEST_WEB_PLATFORM_URL_1; - testWidgets('getHtml', (WidgetTester tester) async { + skippableTestWidgets('getHtml', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/get_meta_tags.dart b/example/integration_test/in_app_webview/get_meta_tags.dart index 647c734a..e30b703e 100644 --- a/example/integration_test/in_app_webview/get_meta_tags.dart +++ b/example/integration_test/in_app_webview/get_meta_tags.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void getMetaTags() { final shouldSkip = kIsWeb @@ -18,7 +11,7 @@ void getMetaTags() { var url = !kIsWeb ? TEST_CROSS_PLATFORM_URL_1 : TEST_WEB_PLATFORM_URL_1; - testWidgets('getMetaTags', (WidgetTester tester) async { + skippableTestWidgets('getMetaTags', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/get_meta_theme_color.dart b/example/integration_test/in_app_webview/get_meta_theme_color.dart index 745ec13c..15f8fe86 100644 --- a/example/integration_test/in_app_webview/get_meta_theme_color.dart +++ b/example/integration_test/in_app_webview/get_meta_theme_color.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void getMetaThemeColor() { final shouldSkip = kIsWeb @@ -18,7 +11,7 @@ void getMetaThemeColor() { var url = !kIsWeb ? TEST_URL_1 : TEST_WEB_PLATFORM_URL_1; - testWidgets('getMetaThemeColor', (WidgetTester tester) async { + skippableTestWidgets('getMetaThemeColor', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/get_original_url.dart b/example/integration_test/in_app_webview/get_original_url.dart index 7cd3612f..635e95d9 100644 --- a/example/integration_test/in_app_webview/get_original_url.dart +++ b/example/integration_test/in_app_webview/get_original_url.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void getOriginalUrl() { final shouldSkip = kIsWeb @@ -18,7 +11,7 @@ void getOriginalUrl() { var url = !kIsWeb ? TEST_URL_1 : TEST_WEB_PLATFORM_URL_1; - testWidgets('getOriginalUrl', (WidgetTester tester) async { + skippableTestWidgets('getOriginalUrl', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/get_progress.dart b/example/integration_test/in_app_webview/get_progress.dart index d46453cd..e550307c 100644 --- a/example/integration_test/in_app_webview/get_progress.dart +++ b/example/integration_test/in_app_webview/get_progress.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void getProgress() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void getProgress() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('getProgress', (WidgetTester tester) async { + skippableTestWidgets('getProgress', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/get_title.dart b/example/integration_test/in_app_webview/get_title.dart index 9c8beb8f..dcd49224 100644 --- a/example/integration_test/in_app_webview/get_title.dart +++ b/example/integration_test/in_app_webview/get_title.dart @@ -1,12 +1,4 @@ -import 'dart:async'; -import 'dart:convert'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void getTitle() { final shouldSkip = kIsWeb @@ -33,7 +25,7 @@ void getTitle() { : TEST_WEB_PLATFORM_URL_1; var expectedValue = !kIsWeb ? 'Some title' : 'page'; - testWidgets('getTitle', (WidgetTester tester) async { + skippableTestWidgets('getTitle', (WidgetTester tester) async { final Completer pageStarted = Completer(); final Completer pageLoaded = Completer(); final Completer controllerCompleter = diff --git a/example/integration_test/in_app_webview/handles_url_scheme.dart b/example/integration_test/in_app_webview/handles_url_scheme.dart index e501856a..87f24f61 100644 --- a/example/integration_test/in_app_webview/handles_url_scheme.dart +++ b/example/integration_test/in_app_webview/handles_url_scheme.dart @@ -1,6 +1,4 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; +part of 'main.dart'; void handlesURLScheme() { final shouldSkip = kIsWeb @@ -10,7 +8,7 @@ void handlesURLScheme() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - test('handlesURLScheme', () async { + skippableTest('handlesURLScheme', () async { expect(await InAppWebViewController.handlesURLScheme("http"), true); expect(await InAppWebViewController.handlesURLScheme("https"), true); }, skip: shouldSkip); diff --git a/example/integration_test/in_app_webview/http_auth_credential_database.dart b/example/integration_test/in_app_webview/http_auth_credential_database.dart index 0f41785a..fc1ebef5 100644 --- a/example/integration_test/in_app_webview/http_auth_credential_database.dart +++ b/example/integration_test/in_app_webview/http_auth_credential_database.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../env.dart'; +part of 'main.dart'; void httpAuthCredentialDatabase() { final shouldSkip = kIsWeb @@ -16,8 +9,8 @@ void httpAuthCredentialDatabase() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - group('Http Auth Credential Database', () { - testWidgets('use saved credentials', (WidgetTester tester) async { + skippableGroup('Http Auth Credential Database', () { + skippableTestWidgets('use saved credentials', (WidgetTester tester) async { HttpAuthCredentialDatabase httpAuthCredentialDatabase = HttpAuthCredentialDatabase.instance(); final Completer controllerCompleter = @@ -83,7 +76,7 @@ void httpAuthCredentialDatabase() { expect(credentials, isEmpty); }); - testWidgets('save credentials', (WidgetTester tester) async { + skippableTestWidgets('save credentials', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/initial_url_request.dart b/example/integration_test/in_app_webview/initial_url_request.dart index e25b0db0..792467b3 100644 --- a/example/integration_test/in_app_webview/initial_url_request.dart +++ b/example/integration_test/in_app_webview/initial_url_request.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void initialUrlRequest() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void initialUrlRequest() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - group('initial url request', () { + skippableGroup('initial url request', () { final shouldSkipTest2 = kIsWeb ? true : ![ @@ -24,7 +17,8 @@ void initialUrlRequest() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('launches with allowsBackForwardNavigationGestures true', + skippableTestWidgets( + 'launches with allowsBackForwardNavigationGestures true', (WidgetTester tester) async { final Completer pageLoaded = Completer(); final Completer controllerCompleter = @@ -66,7 +60,7 @@ void initialUrlRequest() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('basic', (WidgetTester tester) async { + skippableTestWidgets('basic', (WidgetTester tester) async { final Completer pageLoaded = Completer(); final Completer controllerCompleter = Completer(); diff --git a/example/integration_test/in_app_webview/inject_css.dart b/example/integration_test/in_app_webview/inject_css.dart index db19a0f6..cb556394 100644 --- a/example/integration_test/in_app_webview/inject_css.dart +++ b/example/integration_test/in_app_webview/inject_css.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void injectCSS() { final shouldSkip = kIsWeb @@ -18,8 +11,8 @@ void injectCSS() { var url = !kIsWeb ? TEST_URL_ABOUT_BLANK : TEST_WEB_PLATFORM_URL_1; - group('inject CSS', () { - testWidgets('code', (WidgetTester tester) async { + skippableGroup('inject CSS', () { + skippableTestWidgets('code', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); @@ -58,7 +51,7 @@ void injectCSS() { expect(backgroundColor, 'rgb(0, 0, 255)'); }); - testWidgets('file from url', (WidgetTester tester) async { + skippableTestWidgets('file from url', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); @@ -94,7 +87,7 @@ void injectCSS() { false); }); - testWidgets('file from asset', (WidgetTester tester) async { + skippableTestWidgets('file from asset', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/inject_javascript_file.dart b/example/integration_test/in_app_webview/inject_javascript_file.dart index 42413483..1f60b5c0 100644 --- a/example/integration_test/in_app_webview/inject_javascript_file.dart +++ b/example/integration_test/in_app_webview/inject_javascript_file.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void injectJavascriptFile() { final shouldSkip = kIsWeb @@ -18,8 +11,8 @@ void injectJavascriptFile() { var url = !kIsWeb ? TEST_URL_ABOUT_BLANK : TEST_WEB_PLATFORM_URL_1; - group('inject javascript file', () { - testWidgets('from url', (WidgetTester tester) async { + skippableGroup('inject javascript file', () { + skippableTestWidgets('from url', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); @@ -81,7 +74,7 @@ void injectJavascriptFile() { false); }); - testWidgets('from asset', (WidgetTester tester) async { + skippableTestWidgets('from asset', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/intercept_ajax_request.dart b/example/integration_test/in_app_webview/intercept_ajax_request.dart index d9ffadfd..dfcec00b 100644 --- a/example/integration_test/in_app_webview/intercept_ajax_request.dart +++ b/example/integration_test/in_app_webview/intercept_ajax_request.dart @@ -1,12 +1,4 @@ -import 'dart:async'; -import 'dart:convert'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../env.dart'; +part of 'main.dart'; void interceptAjaxRequest() { final shouldSkip = kIsWeb @@ -17,8 +9,8 @@ void interceptAjaxRequest() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - group('intercept ajax request', () { - testWidgets('send string data', (WidgetTester tester) async { + skippableGroup('intercept ajax request', () { + skippableTestWidgets('send string data', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer shouldInterceptAjaxPostRequestCompleter = @@ -100,7 +92,7 @@ void interceptAjaxRequest() { true); }); - testWidgets('send json data', (WidgetTester tester) async { + skippableTestWidgets('send json data', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer shouldInterceptAjaxPostRequestCompleter = @@ -188,7 +180,8 @@ void interceptAjaxRequest() { true); }); - testWidgets('send URLSearchParams data', (WidgetTester tester) async { + skippableTestWidgets('send URLSearchParams data', + (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer shouldInterceptAjaxPostRequestCompleter = @@ -272,7 +265,7 @@ void interceptAjaxRequest() { true); }); - testWidgets('send FormData', (WidgetTester tester) async { + skippableTestWidgets('send FormData', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer shouldInterceptAjaxPostRequestCompleter = diff --git a/example/integration_test/in_app_webview/intercept_fetch_request.dart b/example/integration_test/in_app_webview/intercept_fetch_request.dart index fa8ab863..982dee13 100644 --- a/example/integration_test/in_app_webview/intercept_fetch_request.dart +++ b/example/integration_test/in_app_webview/intercept_fetch_request.dart @@ -1,12 +1,4 @@ -import 'dart:async'; -import 'dart:convert'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../env.dart'; +part of 'main.dart'; void interceptFetchRequest() { final shouldSkip = kIsWeb @@ -17,8 +9,8 @@ void interceptFetchRequest() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - group('intercept fetch request', () { - testWidgets('send string data', (WidgetTester tester) async { + skippableGroup('intercept fetch request', () { + skippableTestWidgets('send string data', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer> fetchPostCompleter = @@ -93,7 +85,7 @@ void interceptFetchRequest() { true); }); - testWidgets('send json data', (WidgetTester tester) async { + skippableTestWidgets('send json data', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer> fetchPostCompleter = @@ -174,7 +166,8 @@ void interceptFetchRequest() { true); }); - testWidgets('send URLSearchParams data', (WidgetTester tester) async { + skippableTestWidgets('send URLSearchParams data', + (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer> fetchPostCompleter = @@ -251,7 +244,7 @@ void interceptFetchRequest() { true); }); - testWidgets('send FormData', (WidgetTester tester) async { + skippableTestWidgets('send FormData', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer> fetchPostCompleter = diff --git a/example/integration_test/in_app_webview/is_loading.dart b/example/integration_test/in_app_webview/is_loading.dart index c963280d..3323e7fc 100644 --- a/example/integration_test/in_app_webview/is_loading.dart +++ b/example/integration_test/in_app_webview/is_loading.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void isLoading() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void isLoading() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('isLoading', (WidgetTester tester) async { + skippableTestWidgets('isLoading', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageStarted = Completer(); diff --git a/example/integration_test/in_app_webview/is_secure_context.dart b/example/integration_test/in_app_webview/is_secure_context.dart index 938be690..3c5d8a6c 100644 --- a/example/integration_test/in_app_webview/is_secure_context.dart +++ b/example/integration_test/in_app_webview/is_secure_context.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void isSecureContext() { final shouldSkip = kIsWeb @@ -18,7 +11,7 @@ void isSecureContext() { var url = !kIsWeb ? TEST_CROSS_PLATFORM_URL_1 : TEST_WEB_PLATFORM_URL_1; - testWidgets('isSecureContext', (WidgetTester tester) async { + skippableTestWidgets('isSecureContext', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = diff --git a/example/integration_test/in_app_webview/javascript_code_evaluation.dart b/example/integration_test/in_app_webview/javascript_code_evaluation.dart index d795045f..8f9a683f 100644 --- a/example/integration_test/in_app_webview/javascript_code_evaluation.dart +++ b/example/integration_test/in_app_webview/javascript_code_evaluation.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void javascriptCodeEvaluation() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void javascriptCodeEvaluation() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - group('javascript code evaluation', () { + skippableGroup('javascript code evaluation', () { final shouldSkipTest1 = kIsWeb ? false : ![ @@ -25,7 +18,7 @@ void javascriptCodeEvaluation() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('evaluateJavascript', (WidgetTester tester) async { + skippableTestWidgets('evaluateJavascript', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); @@ -68,7 +61,7 @@ void javascriptCodeEvaluation() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('evaluateJavascript with content world', + skippableTestWidgets('evaluateJavascript with content world', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); @@ -113,7 +106,7 @@ void javascriptCodeEvaluation() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('callAsyncJavaScript', (WidgetTester tester) async { + skippableTestWidgets('callAsyncJavaScript', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); @@ -174,7 +167,7 @@ void javascriptCodeEvaluation() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('callAsyncJavaScript with content world', + skippableTestWidgets('callAsyncJavaScript with content world', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); diff --git a/example/integration_test/in_app_webview/javascript_dialogs.dart b/example/integration_test/in_app_webview/javascript_dialogs.dart index 4720530c..6b465425 100644 --- a/example/integration_test/in_app_webview/javascript_dialogs.dart +++ b/example/integration_test/in_app_webview/javascript_dialogs.dart @@ -1,9 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; +part of 'main.dart'; void javascriptDialogs() { final shouldSkip = kIsWeb @@ -14,7 +9,7 @@ void javascriptDialogs() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('javascript dialogs', (WidgetTester tester) async { + skippableTestWidgets('javascript dialogs', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/javascript_handler.dart b/example/integration_test/in_app_webview/javascript_handler.dart index 3d379236..5658ca62 100644 --- a/example/integration_test/in_app_webview/javascript_handler.dart +++ b/example/integration_test/in_app_webview/javascript_handler.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../util.dart'; +part of 'main.dart'; void javascriptHandler() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void javascriptHandler() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('JavaScript Handler', (WidgetTester tester) async { + skippableTestWidgets('JavaScript Handler', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageStarted = Completer(); diff --git a/example/integration_test/in_app_webview/keep_alive.dart b/example/integration_test/in_app_webview/keep_alive.dart new file mode 100644 index 00000000..dac09ac3 --- /dev/null +++ b/example/integration_test/in_app_webview/keep_alive.dart @@ -0,0 +1,76 @@ +part of 'main.dart'; + +void keepAlive() { + final shouldSkip = kIsWeb + ? true + : ![ + TargetPlatform.android, + TargetPlatform.iOS, + TargetPlatform.macOS, + ].contains(defaultTargetPlatform); + + final initialUrl = + !kIsWeb ? TEST_CROSS_PLATFORM_URL_1 : TEST_WEB_PLATFORM_URL_1; + + skippableTestWidgets('Keep Alive', (WidgetTester tester) async { + final keepAlive = InAppWebViewKeepAlive(); + + final Completer controllerCompleter = + Completer(); + final Completer controllerCompleter2 = + Completer(); + final Completer pageLoaded = Completer(); + final Completer pageLoaded2 = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: InAppWebView( + key: GlobalKey(), + keepAlive: keepAlive, + initialUrlRequest: URLRequest(url: initialUrl), + onWebViewCreated: (controller) { + controllerCompleter.complete(controller); + }, + onLoadStop: (controller, url) { + if (!pageLoaded.isCompleted && + initialUrl.toString() == url.toString()) { + pageLoaded.complete(); + } + if (!pageLoaded2.isCompleted && + TEST_CROSS_PLATFORM_URL_2.toString() == url.toString()) { + pageLoaded2.complete(); + } + }, + ), + ), + ); + + final InAppWebViewController controller = await controllerCompleter.future; + await pageLoaded.future; + + await controller.loadUrl( + urlRequest: URLRequest(url: TEST_CROSS_PLATFORM_URL_2)); + await pageLoaded2.future; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: InAppWebView( + key: GlobalKey(), + keepAlive: keepAlive, + onWebViewCreated: (controller) { + controllerCompleter2.complete(controller); + }, + )), + ); + final InAppWebViewController controller2 = + await controllerCompleter2.future; + + final String? currentUrl = (await controller2.getUrl())?.toString(); + expect(currentUrl, TEST_CROSS_PLATFORM_URL_2.toString()); + + await expectLater( + InAppWebViewController.disposeKeepAlive(keepAlive), completes); + }, skip: shouldSkip); +} diff --git a/example/integration_test/in_app_webview/load_data.dart b/example/integration_test/in_app_webview/load_data.dart index 3b6dddc3..e5fb32ee 100644 --- a/example/integration_test/in_app_webview/load_data.dart +++ b/example/integration_test/in_app_webview/load_data.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void loadData() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void loadData() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('loadData', (WidgetTester tester) async { + skippableTestWidgets('loadData', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = diff --git a/example/integration_test/in_app_webview/load_file.dart b/example/integration_test/in_app_webview/load_file.dart index a82d515c..09dbbcc8 100644 --- a/example/integration_test/in_app_webview/load_file.dart +++ b/example/integration_test/in_app_webview/load_file.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void loadFile() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void loadFile() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('loadFile', (WidgetTester tester) async { + skippableTestWidgets('loadFile', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = diff --git a/example/integration_test/in_app_webview/load_file_url.dart b/example/integration_test/in_app_webview/load_file_url.dart index a2f69f9c..b4838881 100644 --- a/example/integration_test/in_app_webview/load_file_url.dart +++ b/example/integration_test/in_app_webview/load_file_url.dart @@ -1,11 +1,4 @@ -import 'dart:async'; -import 'dart:io'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:path_provider/path_provider.dart'; +part of 'main.dart'; void loadFileUrl() { final shouldSkip = kIsWeb @@ -15,7 +8,7 @@ void loadFileUrl() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - group('load file URL', () { + skippableGroup('load file URL', () { late Directory appSupportDir; late File fileHtml; late File fileJs; @@ -53,7 +46,8 @@ void loadFileUrl() { fileJs.writeAsStringSync(js); }); - testWidgets('initialUrl with file:// scheme and allowingReadAccessTo', + skippableTestWidgets( + 'initialUrl with file:// scheme and allowingReadAccessTo', (WidgetTester tester) async { final Completer consoleMessageShouldNotComplete = Completer(); @@ -97,7 +91,8 @@ void loadFileUrl() { expect(consoleMessage.message, 'message'); }); - testWidgets('loadUrl with file:// scheme and allowingReadAccessTo argument', + skippableTestWidgets( + 'loadUrl with file:// scheme and allowingReadAccessTo argument', (WidgetTester tester) async { final Completer consoleMessageShouldNotComplete = Completer(); diff --git a/example/integration_test/in_app_webview/load_url.dart b/example/integration_test/in_app_webview/load_url.dart index 8e76ed11..bdb1f5be 100644 --- a/example/integration_test/in_app_webview/load_url.dart +++ b/example/integration_test/in_app_webview/load_url.dart @@ -1,13 +1,4 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:typed_data'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void loadUrl() { final shouldSkip1 = kIsWeb @@ -20,7 +11,7 @@ void loadUrl() { var initialUrl = !kIsWeb ? TEST_URL_1 : TEST_WEB_PLATFORM_URL_1; - testWidgets('loadUrl', (WidgetTester tester) async { + skippableTestWidgets('loadUrl', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer firstUrlLoad = Completer(); @@ -62,7 +53,7 @@ void loadUrl() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('loadSimulatedRequest', (WidgetTester tester) async { + skippableTestWidgets('loadSimulatedRequest', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer firstUrlLoad = Completer(); diff --git a/example/integration_test/in_app_webview/main.dart b/example/integration_test/in_app_webview/main.dart index c1dff0c2..f98ae5d1 100644 --- a/example/integration_test/in_app_webview/main.dart +++ b/example/integration_test/in_app_webview/main.dart @@ -1,95 +1,199 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_test/flutter_test.dart'; +import 'dart:async'; +import 'dart:convert'; +import 'dart:typed_data'; +import 'dart:io'; +import 'dart:collection'; -import 'apple_pay_api.dart'; -import 'audio_playback_policy.dart'; -import 'clear_cache.dart'; -import 'clear_client_cert_preferences.dart'; -import 'clear_focus.dart'; -import 'clear_ssl_preferences.dart'; -import 'content_blocker.dart'; -import 'create_pdf.dart'; -import 'get_certificate.dart'; -import 'get_content_height.dart'; -import 'get_current_web_view_package.dart'; -import 'get_default_user_agent.dart'; -import 'get_favicons.dart'; -import 'get_html.dart'; -import 'get_meta_tags.dart'; -import 'get_meta_theme_color.dart'; -import 'get_original_url.dart'; -import 'get_progress.dart'; -import 'get_title.dart'; -import 'handles_url_scheme.dart'; -import 'http_auth_credential_database.dart'; -import 'initial_url_request.dart'; -import 'inject_css.dart'; -import 'inject_javascript_file.dart'; -import 'intercept_ajax_request.dart'; -import 'intercept_fetch_request.dart'; -import 'is_loading.dart'; -import 'is_secure_context.dart'; -import 'javascript_code_evaluation.dart'; -import 'javascript_dialogs.dart'; -import 'javascript_handler.dart'; -import 'load_data.dart'; -import 'load_file.dart'; -import 'load_file_url.dart'; -import 'load_url.dart'; -import 'on_console_message.dart'; -import 'on_content_size_changed.dart'; -import 'on_download_start_request.dart'; -import 'on_js_before_unload.dart'; -import 'on_received_error.dart'; -import 'on_received_http_error.dart'; -import 'on_load_resource.dart'; -import 'on_load_resource_with_custom_scheme.dart'; -import 'on_navigation_response.dart'; -import 'on_page_commit_visible.dart'; -import 'on_permission_request.dart'; -import 'on_print.dart'; -import 'on_progress_changed.dart'; -import 'on_received_icon.dart'; -import 'on_received_touch_icon_url.dart'; -import 'safe_browsing.dart'; -import 'on_scroll_changed.dart'; -import 'on_title_changed.dart'; -import 'on_update_visited_history.dart'; -import 'on_window_blur.dart'; -import 'on_window_focus.dart'; -import 'page_down_up.dart'; -import 'pause_resume.dart'; -import 'programmatic_zoom_scale.dart'; -import 'pause_resume_timers.dart'; -import 'post_requests.dart'; -import 'print_current_page.dart'; -import 'programmatic_scroll.dart'; -import 'pull_to_refresh.dart'; -import 'reload.dart'; -import 'request_focus_node_href.dart'; -import 'request_image_ref.dart'; -import 'resize_webview.dart'; -import 'web_archive.dart'; -import 'set_custom_useragent.dart'; -import 'set_get_settings.dart'; -import 'set_web_contents_debugging_enabled.dart'; -import 'should_intercept_request.dart'; -import 'should_override_url_loading.dart'; -import 'ssl_request.dart'; -import 'stop_loading.dart'; -import 't_rex_runner_game.dart'; -import 'take_screenshot.dart'; -import 'user_scripts.dart'; -import 'video_playback_policy.dart'; -import 'web_history.dart'; -import 'web_message.dart'; -import 'webview_asset_loader.dart'; -import 'webview_windows.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path_provider/path_provider.dart'; +import '../util.dart'; +import '../constants.dart'; +import '../env.dart'; + +part 'apple_pay_api.dart'; + +part 'audio_playback_policy.dart'; + +part 'clear_cache.dart'; + +part 'clear_client_cert_preferences.dart'; + +part 'clear_focus.dart'; + +part 'clear_ssl_preferences.dart'; + +part 'content_blocker.dart'; + +part 'create_pdf.dart'; + +part 'get_certificate.dart'; + +part 'get_content_height.dart'; + +part 'get_current_web_view_package.dart'; + +part 'get_default_user_agent.dart'; + +part 'get_favicons.dart'; + +part 'get_html.dart'; + +part 'get_meta_tags.dart'; + +part 'get_meta_theme_color.dart'; + +part 'get_original_url.dart'; + +part 'get_progress.dart'; + +part 'get_title.dart'; + +part 'handles_url_scheme.dart'; + +part 'http_auth_credential_database.dart'; + +part 'initial_url_request.dart'; + +part 'inject_css.dart'; + +part 'inject_javascript_file.dart'; + +part 'intercept_ajax_request.dart'; + +part 'intercept_fetch_request.dart'; + +part 'is_loading.dart'; + +part 'is_secure_context.dart'; + +part 'javascript_code_evaluation.dart'; + +part 'javascript_dialogs.dart'; + +part 'javascript_handler.dart'; + +part 'load_data.dart'; + +part 'load_file.dart'; + +part 'load_file_url.dart'; + +part 'load_url.dart'; + +part 'on_console_message.dart'; + +part 'on_content_size_changed.dart'; + +part 'on_download_start_request.dart'; + +part 'on_js_before_unload.dart'; + +part 'on_received_error.dart'; + +part 'on_received_http_error.dart'; + +part 'on_load_resource.dart'; + +part 'on_load_resource_with_custom_scheme.dart'; + +part 'on_navigation_response.dart'; + +part 'on_page_commit_visible.dart'; + +part 'on_permission_request.dart'; + +part 'on_print.dart'; + +part 'on_progress_changed.dart'; + +part 'on_received_icon.dart'; + +part 'on_received_touch_icon_url.dart'; + +part 'safe_browsing.dart'; + +part 'on_scroll_changed.dart'; + +part 'on_title_changed.dart'; + +part 'on_update_visited_history.dart'; + +part 'on_window_blur.dart'; + +part 'on_window_focus.dart'; + +part 'page_down_up.dart'; + +part 'pause_resume.dart'; + +part 'programmatic_zoom_scale.dart'; + +part 'pause_resume_timers.dart'; + +part 'post_requests.dart'; + +part 'print_current_page.dart'; + +part 'programmatic_scroll.dart'; + +part 'pull_to_refresh.dart'; + +part 'reload.dart'; + +part 'request_focus_node_href.dart'; + +part 'request_image_ref.dart'; + +part 'resize_webview.dart'; + +part 'web_archive.dart'; + +part 'set_custom_useragent.dart'; + +part 'set_get_settings.dart'; + +part 'set_web_contents_debugging_enabled.dart'; + +part 'should_intercept_request.dart'; + +part 'should_override_url_loading.dart'; + +part 'ssl_request.dart'; + +part 'stop_loading.dart'; + +part 't_rex_runner_game.dart'; + +part 'take_screenshot.dart'; + +part 'user_scripts.dart'; + +part 'video_playback_policy.dart'; + +part 'web_history.dart'; + +part 'web_message.dart'; + +part 'webview_asset_loader.dart'; + +part 'webview_windows.dart'; + +part 'keep_alive.dart'; void main() { - final shouldSkip = [TargetPlatform.macOS].contains(defaultTargetPlatform); + final shouldSkip = kIsWeb + ? false + : ![ + TargetPlatform.android, + TargetPlatform.iOS, + ].contains(defaultTargetPlatform); - group('InAppWebView', () { + skippableGroup('InAppWebView', () { initialUrlRequest(); setGetSettings(); javascriptCodeEvaluation(); @@ -174,5 +278,6 @@ void main() { handlesURLScheme(); webViewAssetLoader(); onContentSizeChanged(); + keepAlive(); }, skip: shouldSkip); } diff --git a/example/integration_test/in_app_webview/on_console_message.dart b/example/integration_test/in_app_webview/on_console_message.dart index 09cd4f06..495d12c4 100644 --- a/example/integration_test/in_app_webview/on_console_message.dart +++ b/example/integration_test/in_app_webview/on_console_message.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void onConsoleMessage() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void onConsoleMessage() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('onConsoleMessage', (WidgetTester tester) async { + skippableTestWidgets('onConsoleMessage', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer onConsoleMessageCompleter = diff --git a/example/integration_test/in_app_webview/on_content_size_changed.dart b/example/integration_test/in_app_webview/on_content_size_changed.dart index 7b7b927d..318c3ba7 100644 --- a/example/integration_test/in_app_webview/on_content_size_changed.dart +++ b/example/integration_test/in_app_webview/on_content_size_changed.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void onContentSizeChanged() { final shouldSkip = kIsWeb @@ -15,7 +8,7 @@ void onContentSizeChanged() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('onContentSizeChanged', (WidgetTester tester) async { + skippableTestWidgets('onContentSizeChanged', (WidgetTester tester) async { final Completer onContentSizeChangedCompleter = Completer(); await tester.pumpWidget( Directionality( diff --git a/example/integration_test/in_app_webview/on_download_start_request.dart b/example/integration_test/in_app_webview/on_download_start_request.dart index be3f2b41..ba735534 100644 --- a/example/integration_test/in_app_webview/on_download_start_request.dart +++ b/example/integration_test/in_app_webview/on_download_start_request.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../env.dart'; +part of 'main.dart'; void onDownloadStartRequest() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void onDownloadStartRequest() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('onDownloadStartRequest', (WidgetTester tester) async { + skippableTestWidgets('onDownloadStartRequest', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer onDownloadStartCompleter = Completer(); diff --git a/example/integration_test/in_app_webview/on_js_before_unload.dart b/example/integration_test/in_app_webview/on_js_before_unload.dart index 0c43b8d1..19471c59 100644 --- a/example/integration_test/in_app_webview/on_js_before_unload.dart +++ b/example/integration_test/in_app_webview/on_js_before_unload.dart @@ -1,8 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; +part of 'main.dart'; void onJsBeforeUnload() { // final shouldSkip = kIsWeb @@ -12,7 +8,7 @@ void onJsBeforeUnload() { // ].contains(defaultTargetPlatform); final shouldSkip = true; // on Android, for some reason, it works on an example app but not in this test - testWidgets('onJsBeforeUnload', (WidgetTester tester) async { + skippableTestWidgets('onJsBeforeUnload', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer onJsBeforeUnloadCompleter = Completer(); diff --git a/example/integration_test/in_app_webview/on_load_resource.dart b/example/integration_test/in_app_webview/on_load_resource.dart index 3b732a4d..b31db431 100644 --- a/example/integration_test/in_app_webview/on_load_resource.dart +++ b/example/integration_test/in_app_webview/on_load_resource.dart @@ -1,9 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; +part of 'main.dart'; void onLoadResource() { final shouldSkip = kIsWeb @@ -14,7 +9,7 @@ void onLoadResource() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('onLoadResource', (WidgetTester tester) async { + skippableTestWidgets('onLoadResource', (WidgetTester tester) async { List resourceList = [ "https://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css", "https://code.jquery.com/jquery-3.3.1.min.js", diff --git a/example/integration_test/in_app_webview/on_load_resource_with_custom_scheme.dart b/example/integration_test/in_app_webview/on_load_resource_with_custom_scheme.dart index 3c4dce4f..4b0964f1 100644 --- a/example/integration_test/in_app_webview/on_load_resource_with_custom_scheme.dart +++ b/example/integration_test/in_app_webview/on_load_resource_with_custom_scheme.dart @@ -1,10 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; +part of 'main.dart'; void onLoadResourceWithCustomScheme() { final shouldSkip = kIsWeb @@ -15,7 +9,8 @@ void onLoadResourceWithCustomScheme() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('onLoadResourceWithCustomScheme', (WidgetTester tester) async { + skippableTestWidgets('onLoadResourceWithCustomScheme', + (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer imageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/on_navigation_response.dart b/example/integration_test/in_app_webview/on_navigation_response.dart index c21cbbde..70aea1d9 100644 --- a/example/integration_test/in_app_webview/on_navigation_response.dart +++ b/example/integration_test/in_app_webview/on_navigation_response.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void onNavigationResponse() { final shouldSkip = kIsWeb @@ -15,8 +8,8 @@ void onNavigationResponse() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - group("onNavigationResponse", () { - testWidgets('allow navigation', (WidgetTester tester) async { + skippableGroup('onNavigationResponse', () { + skippableTestWidgets('allow navigation', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); @@ -49,7 +42,7 @@ void onNavigationResponse() { expect(url, TEST_URL_1.toString()); }); - testWidgets('cancel navigation', (WidgetTester tester) async { + skippableTestWidgets('cancel navigation', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/on_page_commit_visible.dart b/example/integration_test/in_app_webview/on_page_commit_visible.dart index 4cf628d5..ecfd036d 100644 --- a/example/integration_test/in_app_webview/on_page_commit_visible.dart +++ b/example/integration_test/in_app_webview/on_page_commit_visible.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void onPageCommitVisible() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void onPageCommitVisible() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('onPageCommitVisible', (WidgetTester tester) async { + skippableTestWidgets('onPageCommitVisible', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer onPageCommitVisibleCompleter = Completer(); diff --git a/example/integration_test/in_app_webview/on_permission_request.dart b/example/integration_test/in_app_webview/on_permission_request.dart index b8f7eb09..115adb27 100644 --- a/example/integration_test/in_app_webview/on_permission_request.dart +++ b/example/integration_test/in_app_webview/on_permission_request.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void onPermissionRequest() { final shouldSkip = kIsWeb @@ -18,7 +11,7 @@ void onPermissionRequest() { final expectedValue = [PermissionResourceType.CAMERA]; - testWidgets('onPermissionRequest', (WidgetTester tester) async { + skippableTestWidgets('onPermissionRequest', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); @@ -66,7 +59,8 @@ void onPermissionRequest() { // TODO: this test is not working final shouldSkip2 = true; - testWidgets('onPermissionRequestCanceled', (WidgetTester tester) async { + skippableTestWidgets('onPermissionRequestCanceled', + (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/on_print.dart b/example/integration_test/in_app_webview/on_print.dart index b594ada5..f4220180 100644 --- a/example/integration_test/in_app_webview/on_print.dart +++ b/example/integration_test/in_app_webview/on_print.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void onPrint() { final shouldSkip = kIsWeb @@ -18,7 +11,7 @@ void onPrint() { var url = !kIsWeb ? TEST_URL_1 : TEST_WEB_PLATFORM_URL_1; - testWidgets('onPrint', (WidgetTester tester) async { + skippableTestWidgets('onPrint', (WidgetTester tester) async { final Completer onPrintCompleter = Completer(); await tester.pumpWidget( Directionality( diff --git a/example/integration_test/in_app_webview/on_progress_changed.dart b/example/integration_test/in_app_webview/on_progress_changed.dart index 96d7c67b..16c20c03 100644 --- a/example/integration_test/in_app_webview/on_progress_changed.dart +++ b/example/integration_test/in_app_webview/on_progress_changed.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void onProgressChanged() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void onProgressChanged() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('onProgressChanged', (WidgetTester tester) async { + skippableTestWidgets('onProgressChanged', (WidgetTester tester) async { final Completer onProgressChangedCompleter = Completer(); await tester.pumpWidget( Directionality( diff --git a/example/integration_test/in_app_webview/on_received_error.dart b/example/integration_test/in_app_webview/on_received_error.dart index 2e45e41b..8e67cc59 100644 --- a/example/integration_test/in_app_webview/on_received_error.dart +++ b/example/integration_test/in_app_webview/on_received_error.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void onReceivedError() { final shouldSkip = kIsWeb @@ -16,8 +9,8 @@ void onReceivedError() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - group('onReceivedError', () { - testWidgets('invalid url', (WidgetTester tester) async { + skippableGroup('onReceivedError', () { + skippableTestWidgets('invalid url', (WidgetTester tester) async { final Completer errorUrlCompleter = Completer(); final Completer errorCodeCompleter = Completer(); @@ -43,7 +36,7 @@ void onReceivedError() { expect(url, TEST_NOT_A_WEBSITE_URL.toString()); }); - testWidgets('event is not called with valid url', + skippableTestWidgets('event is not called with valid url', (WidgetTester tester) async { final Completer onReceivedErrorCompleter = Completer(); diff --git a/example/integration_test/in_app_webview/on_received_http_error.dart b/example/integration_test/in_app_webview/on_received_http_error.dart index 5e6396a4..43905aeb 100644 --- a/example/integration_test/in_app_webview/on_received_http_error.dart +++ b/example/integration_test/in_app_webview/on_received_http_error.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void onReceivedHttpError() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void onReceivedHttpError() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('onReceivedHttpError', (WidgetTester tester) async { + skippableTestWidgets('onReceivedHttpError', (WidgetTester tester) async { final Completer errorUrlCompleter = Completer(); final Completer statusCodeCompleter = Completer(); diff --git a/example/integration_test/in_app_webview/on_received_icon.dart b/example/integration_test/in_app_webview/on_received_icon.dart index f2bf90b8..22d6c5c1 100644 --- a/example/integration_test/in_app_webview/on_received_icon.dart +++ b/example/integration_test/in_app_webview/on_received_icon.dart @@ -1,12 +1,4 @@ -import 'dart:async'; -import 'dart:typed_data'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void onReceivedIcon() { final shouldSkip = kIsWeb @@ -15,7 +7,7 @@ void onReceivedIcon() { TargetPlatform.android, ].contains(defaultTargetPlatform); - testWidgets('onReceivedIcon', (WidgetTester tester) async { + skippableTestWidgets('onReceivedIcon', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/on_received_touch_icon_url.dart b/example/integration_test/in_app_webview/on_received_touch_icon_url.dart index e35cd4d5..3f3e9ad9 100644 --- a/example/integration_test/in_app_webview/on_received_touch_icon_url.dart +++ b/example/integration_test/in_app_webview/on_received_touch_icon_url.dart @@ -1,9 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; +part of 'main.dart'; void onReceivedTouchIconUrl() { final shouldSkip = kIsWeb @@ -12,7 +7,7 @@ void onReceivedTouchIconUrl() { TargetPlatform.android, ].contains(defaultTargetPlatform); - testWidgets('onReceivedTouchIconUrl', (WidgetTester tester) async { + skippableTestWidgets('onReceivedTouchIconUrl', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer onReceivedTouchIconUrlCompleter = diff --git a/example/integration_test/in_app_webview/on_scroll_changed.dart b/example/integration_test/in_app_webview/on_scroll_changed.dart index cb9a8eb8..6903cbc8 100644 --- a/example/integration_test/in_app_webview/on_scroll_changed.dart +++ b/example/integration_test/in_app_webview/on_scroll_changed.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void onScrollChanged() { final shouldSkip = kIsWeb @@ -18,7 +11,7 @@ void onScrollChanged() { var url = !kIsWeb ? TEST_URL_1 : TEST_WEB_PLATFORM_URL_1; - testWidgets('onScrollChanged', (WidgetTester tester) async { + skippableTestWidgets('onScrollChanged', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/on_title_changed.dart b/example/integration_test/in_app_webview/on_title_changed.dart index 0682332c..d0f6fb5a 100644 --- a/example/integration_test/in_app_webview/on_title_changed.dart +++ b/example/integration_test/in_app_webview/on_title_changed.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void onTitleChanged() { final shouldSkip = kIsWeb @@ -18,7 +11,7 @@ void onTitleChanged() { var url = !kIsWeb ? TEST_URL_1 : TEST_WEB_PLATFORM_URL_1; - testWidgets('onTitleChanged', (WidgetTester tester) async { + skippableTestWidgets('onTitleChanged', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/on_update_visited_history.dart b/example/integration_test/in_app_webview/on_update_visited_history.dart index da23b5e2..9976e81e 100644 --- a/example/integration_test/in_app_webview/on_update_visited_history.dart +++ b/example/integration_test/in_app_webview/on_update_visited_history.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void onUpdateVisitedHistory() { final shouldSkip = kIsWeb @@ -18,7 +11,7 @@ void onUpdateVisitedHistory() { var url = !kIsWeb ? TEST_CROSS_PLATFORM_URL_1 : TEST_WEB_PLATFORM_URL_1; - testWidgets('onUpdateVisitedHistory', (WidgetTester tester) async { + skippableTestWidgets('onUpdateVisitedHistory', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer firstPushCompleter = Completer(); diff --git a/example/integration_test/in_app_webview/on_window_blur.dart b/example/integration_test/in_app_webview/on_window_blur.dart index 98fb99da..cb7b3282 100644 --- a/example/integration_test/in_app_webview/on_window_blur.dart +++ b/example/integration_test/in_app_webview/on_window_blur.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void onWindowBlur() { final shouldSkip = kIsWeb @@ -18,7 +11,7 @@ void onWindowBlur() { var url = !kIsWeb ? TEST_URL_1 : TEST_WEB_PLATFORM_URL_1; - testWidgets('onWindowBlur', (WidgetTester tester) async { + skippableTestWidgets('onWindowBlur', (WidgetTester tester) async { final Completer onWindowBlurCompleter = Completer(); await tester.pumpWidget( Directionality( diff --git a/example/integration_test/in_app_webview/on_window_focus.dart b/example/integration_test/in_app_webview/on_window_focus.dart index 6a4bc0bc..c07fe528 100644 --- a/example/integration_test/in_app_webview/on_window_focus.dart +++ b/example/integration_test/in_app_webview/on_window_focus.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void onWindowFocus() { final shouldSkip = kIsWeb @@ -18,7 +11,7 @@ void onWindowFocus() { var url = !kIsWeb ? TEST_URL_1 : TEST_WEB_PLATFORM_URL_1; - testWidgets('onWindowFocus', (WidgetTester tester) async { + skippableTestWidgets('onWindowFocus', (WidgetTester tester) async { final Completer onWindowFocusCompleter = Completer(); await tester.pumpWidget( Directionality( diff --git a/example/integration_test/in_app_webview/page_down_up.dart b/example/integration_test/in_app_webview/page_down_up.dart index 41ae8cca..ccc8e1d1 100644 --- a/example/integration_test/in_app_webview/page_down_up.dart +++ b/example/integration_test/in_app_webview/page_down_up.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void pageDownUp() { final shouldSkip = kIsWeb @@ -14,7 +7,7 @@ void pageDownUp() { TargetPlatform.android, ].contains(defaultTargetPlatform); - testWidgets('pageDown/pageUp', (WidgetTester tester) async { + skippableTestWidgets('pageDown/pageUp', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/pause_resume.dart b/example/integration_test/in_app_webview/pause_resume.dart index 975e7944..9c4c80f2 100644 --- a/example/integration_test/in_app_webview/pause_resume.dart +++ b/example/integration_test/in_app_webview/pause_resume.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void pauseResume() { final shouldSkip = kIsWeb @@ -14,7 +7,7 @@ void pauseResume() { TargetPlatform.android, ].contains(defaultTargetPlatform); - testWidgets('pause/resume', (WidgetTester tester) async { + skippableTestWidgets('pause/resume', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/pause_resume_timers.dart b/example/integration_test/in_app_webview/pause_resume_timers.dart index 9e19af24..e00fa6f9 100644 --- a/example/integration_test/in_app_webview/pause_resume_timers.dart +++ b/example/integration_test/in_app_webview/pause_resume_timers.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void pauseResumeTimers() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void pauseResumeTimers() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('pause/resume timers', (WidgetTester tester) async { + skippableTestWidgets('pause/resume timers', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/post_requests.dart b/example/integration_test/in_app_webview/post_requests.dart index ac391a59..d771e533 100644 --- a/example/integration_test/in_app_webview/post_requests.dart +++ b/example/integration_test/in_app_webview/post_requests.dart @@ -1,13 +1,4 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:typed_data'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../env.dart'; +part of 'main.dart'; void postRequests() { final shouldSkip = kIsWeb @@ -18,8 +9,8 @@ void postRequests() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - group('POST requests', () { - testWidgets('initialUrlRequest', (WidgetTester tester) async { + skippableGroup('POST requests', () { + skippableTestWidgets('initialUrlRequest', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer postPageLoaded = Completer(); @@ -58,7 +49,7 @@ void postRequests() { expect(pContent, "HELLO FooBar!"); }); - testWidgets('loadUrl', (WidgetTester tester) async { + skippableTestWidgets('loadUrl', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer postPageLoaded = Completer(); @@ -104,7 +95,7 @@ void postRequests() { expect(pContent, "HELLO FooBar!"); }); - testWidgets('postUrl', (WidgetTester tester) async { + skippableTestWidgets('postUrl', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer postPageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/print_current_page.dart b/example/integration_test/in_app_webview/print_current_page.dart index a367585e..13a11c0f 100644 --- a/example/integration_test/in_app_webview/print_current_page.dart +++ b/example/integration_test/in_app_webview/print_current_page.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void printCurrentPage() { final shouldSkip = kIsWeb @@ -18,7 +11,7 @@ void printCurrentPage() { var url = !kIsWeb ? TEST_CROSS_PLATFORM_URL_1 : TEST_WEB_PLATFORM_URL_1; - testWidgets('printCurrentPage', (WidgetTester tester) async { + skippableTestWidgets('printCurrentPage', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/programmatic_scroll.dart b/example/integration_test/in_app_webview/programmatic_scroll.dart index f65aff24..640e7129 100644 --- a/example/integration_test/in_app_webview/programmatic_scroll.dart +++ b/example/integration_test/in_app_webview/programmatic_scroll.dart @@ -1,12 +1,4 @@ -import 'dart:async'; -import 'dart:convert'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void programmaticScroll() { final shouldSkip = kIsWeb @@ -17,7 +9,7 @@ void programmaticScroll() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - group('Programmatic Scroll', () { + skippableGroup('Programmatic Scroll', () { final shouldSkipTest1 = kIsWeb ? false : ![ @@ -26,7 +18,8 @@ void programmaticScroll() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('set and get scroll position', (WidgetTester tester) async { + skippableTestWidgets('set and get scroll position', + (WidgetTester tester) async { final String scrollTestPage = ''' diff --git a/example/integration_test/in_app_webview/programmatic_zoom_scale.dart b/example/integration_test/in_app_webview/programmatic_zoom_scale.dart index 7a0a942d..5694f5c0 100644 --- a/example/integration_test/in_app_webview/programmatic_zoom_scale.dart +++ b/example/integration_test/in_app_webview/programmatic_zoom_scale.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void programmaticZoomScale() { final shouldSkip = kIsWeb @@ -16,14 +9,14 @@ void programmaticZoomScale() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - group('programmatic zoom scale', () { + skippableGroup('programmatic zoom scale', () { final shouldSkipTest1 = kIsWeb ? true : ![ TargetPlatform.android, ].contains(defaultTargetPlatform); - testWidgets('zoomIn/zoomOut', (WidgetTester tester) async { + skippableTestWidgets('zoomIn/zoomOut', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); @@ -52,7 +45,7 @@ void programmaticZoomScale() { expect(await controller.zoomOut(), true); }, skip: shouldSkipTest1); - testWidgets('onZoomScaleChanged', (WidgetTester tester) async { + skippableTestWidgets('onZoomScaleChanged', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); @@ -93,7 +86,7 @@ void programmaticZoomScale() { await expectLater(onZoomScaleChangedCompleter.future, completes); }); - testWidgets('zoomBy', (WidgetTester tester) async { + skippableTestWidgets('zoomBy', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); @@ -122,7 +115,7 @@ void programmaticZoomScale() { controller.zoomBy(zoomFactor: 3.0, animated: true), completes); }); - testWidgets('getZoomScale', (WidgetTester tester) async { + skippableTestWidgets('getZoomScale', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/pull_to_refresh.dart b/example/integration_test/in_app_webview/pull_to_refresh.dart index 51fb6d99..8ab88ae7 100644 --- a/example/integration_test/in_app_webview/pull_to_refresh.dart +++ b/example/integration_test/in_app_webview/pull_to_refresh.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void pullToRefresh() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void pullToRefresh() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('launches with pull-to-refresh feature', + skippableTestWidgets('launches with pull-to-refresh feature', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); diff --git a/example/integration_test/in_app_webview/reload.dart b/example/integration_test/in_app_webview/reload.dart index 2fb64a6e..5cdb218d 100644 --- a/example/integration_test/in_app_webview/reload.dart +++ b/example/integration_test/in_app_webview/reload.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void reload() { final shouldSkip = kIsWeb @@ -18,7 +11,7 @@ void reload() { var url = !kIsWeb ? TEST_URL_1 : TEST_WEB_PLATFORM_URL_1; - group('reload', () { + skippableGroup('reload', () { final shouldSkipTest1 = kIsWeb ? true : ![ @@ -26,7 +19,7 @@ void reload() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('from origin', (WidgetTester tester) async { + skippableTestWidgets('from origin', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); @@ -55,7 +48,7 @@ void reload() { await expectLater(controller.reloadFromOrigin(), completes); }, skip: shouldSkipTest1); - testWidgets('basic', (WidgetTester tester) async { + skippableTestWidgets('basic', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = diff --git a/example/integration_test/in_app_webview/request_focus_node_href.dart b/example/integration_test/in_app_webview/request_focus_node_href.dart index 8e8d9015..36c122fc 100644 --- a/example/integration_test/in_app_webview/request_focus_node_href.dart +++ b/example/integration_test/in_app_webview/request_focus_node_href.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void requestFocusNodeHref() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void requestFocusNodeHref() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('requestFocusNodeHref', (WidgetTester tester) async { + skippableTestWidgets('requestFocusNodeHref', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/request_image_ref.dart b/example/integration_test/in_app_webview/request_image_ref.dart index 0b690ab4..dbefee32 100644 --- a/example/integration_test/in_app_webview/request_image_ref.dart +++ b/example/integration_test/in_app_webview/request_image_ref.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void requestImageRef() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void requestImageRef() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('requestImageRef', (WidgetTester tester) async { + skippableTestWidgets('requestImageRef', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/resize_webview.dart b/example/integration_test/in_app_webview/resize_webview.dart index e6bd5f94..43540d09 100644 --- a/example/integration_test/in_app_webview/resize_webview.dart +++ b/example/integration_test/in_app_webview/resize_webview.dart @@ -1,10 +1,4 @@ -import 'dart:async'; -import 'dart:convert'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; +part of 'main.dart'; void resizeWebView() { final shouldSkip = kIsWeb @@ -15,7 +9,7 @@ void resizeWebView() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('resize webview', (WidgetTester tester) async { + skippableTestWidgets('resize webview', (WidgetTester tester) async { final String resizeTest = ''' Resize test diff --git a/example/integration_test/in_app_webview/safe_browsing.dart b/example/integration_test/in_app_webview/safe_browsing.dart index ae0593e3..3e1cc8fd 100644 --- a/example/integration_test/in_app_webview/safe_browsing.dart +++ b/example/integration_test/in_app_webview/safe_browsing.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void safeBrowsing() { final shouldSkip = kIsWeb @@ -14,8 +7,8 @@ void safeBrowsing() { TargetPlatform.android, ].contains(defaultTargetPlatform); - group('safe browsing', () { - testWidgets('onSafeBrowsingHit', (WidgetTester tester) async { + skippableGroup('safe browsing', () { + skippableTestWidgets('onSafeBrowsingHit', (WidgetTester tester) async { final Completer pageLoaded = Completer(); await tester.pumpWidget( Directionality( @@ -48,12 +41,12 @@ void safeBrowsing() { expect(url, TEST_CHROME_SAFE_BROWSING_MALWARE.toString()); }); - test('getSafeBrowsingPrivacyPolicyUrl', () async { + skippableTest('getSafeBrowsingPrivacyPolicyUrl', () async { expect(await InAppWebViewController.getSafeBrowsingPrivacyPolicyUrl(), isNotNull); }); - test('setSafeBrowsingWhitelist', () async { + skippableTest('setSafeBrowsingWhitelist', () async { expect( await InAppWebViewController.setSafeBrowsingAllowlist( hosts: ["flutter.dev", "github.com"]), diff --git a/example/integration_test/in_app_webview/set_custom_useragent.dart b/example/integration_test/in_app_webview/set_custom_useragent.dart index aec98ada..56c7dc61 100644 --- a/example/integration_test/in_app_webview/set_custom_useragent.dart +++ b/example/integration_test/in_app_webview/set_custom_useragent.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void setCustomUserAgent() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void setCustomUserAgent() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('set custom userAgent', (WidgetTester tester) async { + skippableTestWidgets('set custom userAgent', (WidgetTester tester) async { final Completer controllerCompleter1 = Completer(); await tester.pumpWidget( Directionality( diff --git a/example/integration_test/in_app_webview/set_get_settings.dart b/example/integration_test/in_app_webview/set_get_settings.dart index 514ad867..2c5a6d0f 100644 --- a/example/integration_test/in_app_webview/set_get_settings.dart +++ b/example/integration_test/in_app_webview/set_get_settings.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void setGetSettings() { final shouldSkip = kIsWeb @@ -18,7 +11,7 @@ void setGetSettings() { final url = !kIsWeb ? TEST_CROSS_PLATFORM_URL_1 : TEST_WEB_PLATFORM_URL_1; - testWidgets('set/get settings', (WidgetTester tester) async { + skippableTestWidgets('set/get settings', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/set_web_contents_debugging_enabled.dart b/example/integration_test/in_app_webview/set_web_contents_debugging_enabled.dart index 88056775..34b371f2 100644 --- a/example/integration_test/in_app_webview/set_web_contents_debugging_enabled.dart +++ b/example/integration_test/in_app_webview/set_web_contents_debugging_enabled.dart @@ -1,6 +1,4 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; +part of 'main.dart'; void setWebContentsDebuggingEnabled() { final shouldSkip = kIsWeb @@ -9,7 +7,7 @@ void setWebContentsDebuggingEnabled() { TargetPlatform.android, ].contains(defaultTargetPlatform); - test('setWebContentsDebuggingEnabled', () async { + skippableTest('setWebContentsDebuggingEnabled', () async { expect( InAppWebViewController.setWebContentsDebuggingEnabled(true), completes); }, skip: shouldSkip); diff --git a/example/integration_test/in_app_webview/should_intercept_request.dart b/example/integration_test/in_app_webview/should_intercept_request.dart index 7c697d6f..c3fd7baf 100644 --- a/example/integration_test/in_app_webview/should_intercept_request.dart +++ b/example/integration_test/in_app_webview/should_intercept_request.dart @@ -1,9 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; +part of 'main.dart'; void shouldInterceptRequest() { final shouldSkip = kIsWeb @@ -12,7 +7,7 @@ void shouldInterceptRequest() { TargetPlatform.android, ].contains(defaultTargetPlatform); - testWidgets('shouldInterceptRequest', (WidgetTester tester) async { + skippableTestWidgets('shouldInterceptRequest', (WidgetTester tester) async { List resourceList = [ "https://getbootstrap.com/docs/4.3/dist/css/bootstrap.min.css", "https://code.jquery.com/jquery-3.3.1.min.js", diff --git a/example/integration_test/in_app_webview/should_override_url_loading.dart b/example/integration_test/in_app_webview/should_override_url_loading.dart index 487c3fad..507331e9 100644 --- a/example/integration_test/in_app_webview/should_override_url_loading.dart +++ b/example/integration_test/in_app_webview/should_override_url_loading.dart @@ -1,12 +1,4 @@ -import 'dart:async'; -import 'dart:convert'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void shouldOverrideUrlLoading() { final shouldSkip = kIsWeb @@ -17,13 +9,13 @@ void shouldOverrideUrlLoading() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - group('shouldOverrideUrlLoading', () { + skippableGroup('shouldOverrideUrlLoading', () { final String page = '''flutter_inappwebview'''; final String pageEncoded = 'data:text/html;charset=utf-8;base64,' + base64Encode(const Utf8Encoder().convert(page)); - testWidgets('can allow requests', (WidgetTester tester) async { + skippableTestWidgets('can allow requests', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = @@ -127,7 +119,7 @@ void shouldOverrideUrlLoading() { pageLoads.close(); }, skip: shouldSkipTest2); - testWidgets('can block requests', (WidgetTester tester) async { + skippableTestWidgets('can block requests', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = @@ -175,7 +167,8 @@ void shouldOverrideUrlLoading() { pageLoads.close(); }); - testWidgets('supports asynchronous decisions', (WidgetTester tester) async { + skippableTestWidgets('supports asynchronous decisions', + (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = diff --git a/example/integration_test/in_app_webview/ssl_request.dart b/example/integration_test/in_app_webview/ssl_request.dart index 14554a2d..094c1f20 100644 --- a/example/integration_test/in_app_webview/ssl_request.dart +++ b/example/integration_test/in_app_webview/ssl_request.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../env.dart'; +part of 'main.dart'; void sslRequest() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void sslRequest() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('SSL request', (WidgetTester tester) async { + skippableTestWidgets('SSL request', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/stop_loading.dart b/example/integration_test/in_app_webview/stop_loading.dart index b8b30cbf..a4c2c0d7 100644 --- a/example/integration_test/in_app_webview/stop_loading.dart +++ b/example/integration_test/in_app_webview/stop_loading.dart @@ -1,12 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; -import '../util.dart'; +part of 'main.dart'; void stopLoading() { final shouldSkip = kIsWeb @@ -17,7 +9,7 @@ void stopLoading() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('stopLoading', (WidgetTester tester) async { + skippableTestWidgets('stopLoading', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/t_rex_runner_game.dart b/example/integration_test/in_app_webview/t_rex_runner_game.dart index 5e0f57cb..b1f98295 100644 --- a/example/integration_test/in_app_webview/t_rex_runner_game.dart +++ b/example/integration_test/in_app_webview/t_rex_runner_game.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void tRexRunnerGame() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void tRexRunnerGame() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('T-Rex Runner game', (WidgetTester tester) async { + skippableTestWidgets('T-Rex Runner game', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/take_screenshot.dart b/example/integration_test/in_app_webview/take_screenshot.dart index 47f28e9b..49a126a1 100644 --- a/example/integration_test/in_app_webview/take_screenshot.dart +++ b/example/integration_test/in_app_webview/take_screenshot.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void takeScreenshot() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void takeScreenshot() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('takeScreenshot', (WidgetTester tester) async { + skippableTestWidgets('takeScreenshot', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/user_scripts.dart b/example/integration_test/in_app_webview/user_scripts.dart index 94746494..078218ca 100644 --- a/example/integration_test/in_app_webview/user_scripts.dart +++ b/example/integration_test/in_app_webview/user_scripts.dart @@ -1,12 +1,4 @@ -import 'dart:async'; -import 'dart:collection'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void userScripts() { final shouldSkip = kIsWeb @@ -17,8 +9,8 @@ void userScripts() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - group('user scripts', () { - testWidgets('initialUserScripts', (WidgetTester tester) async { + skippableGroup('user scripts', () { + skippableTestWidgets('initialUserScripts', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); @@ -77,7 +69,8 @@ void userScripts() { 12); }); - testWidgets('add/remove user scripts', (WidgetTester tester) async { + skippableTestWidgets('add/remove user scripts', + (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = diff --git a/example/integration_test/in_app_webview/video_playback_policy.dart b/example/integration_test/in_app_webview/video_playback_policy.dart index ea2ad136..6188967c 100644 --- a/example/integration_test/in_app_webview/video_playback_policy.dart +++ b/example/integration_test/in_app_webview/video_playback_policy.dart @@ -1,12 +1,4 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:typed_data'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; +part of 'main.dart'; void videoPlaybackPolicy() { final shouldSkip = kIsWeb @@ -17,7 +9,7 @@ void videoPlaybackPolicy() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - group('Video playback policy', () { + skippableGroup('Video playback policy', () { String videoTestBase64 = ""; setUpAll(() async { final ByteData videoData = @@ -57,7 +49,7 @@ void videoPlaybackPolicy() { videoTestBase64 = base64Encode(const Utf8Encoder().convert(videoTest)); }); - testWidgets('Auto media playback', (WidgetTester tester) async { + skippableTestWidgets('Auto media playback', (WidgetTester tester) async { Completer controllerCompleter = Completer(); Completer pageLoaded = Completer(); @@ -128,7 +120,8 @@ void videoPlaybackPolicy() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('Video plays inline when allowsInlineMediaPlayback is true', + skippableTestWidgets( + 'Video plays inline when allowsInlineMediaPlayback is true', (WidgetTester tester) async { Completer controllerCompleter = Completer(); @@ -218,7 +211,7 @@ void videoPlaybackPolicy() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); // on Android, entering fullscreen requires user interaction - testWidgets('exit fullscreen event', (WidgetTester tester) async { + skippableTestWidgets('exit fullscreen event', (WidgetTester tester) async { Completer controllerCompleter = Completer(); Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/web_archive.dart b/example/integration_test/in_app_webview/web_archive.dart index 41c5a050..914011ec 100644 --- a/example/integration_test/in_app_webview/web_archive.dart +++ b/example/integration_test/in_app_webview/web_archive.dart @@ -1,13 +1,4 @@ -import 'dart:async'; -import 'dart:io'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:path_provider/path_provider.dart'; - -import '../constants.dart'; +part of 'main.dart'; void webArchive() { final shouldSkip = kIsWeb @@ -18,7 +9,7 @@ void webArchive() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - group('web archive', () { + skippableGroup('web archive', () { final shouldSkipTest1 = kIsWeb ? true : ![ @@ -26,7 +17,7 @@ void webArchive() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('create data', (WidgetTester tester) async { + skippableTestWidgets('create data', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); @@ -54,7 +45,7 @@ void webArchive() { expect(await controller.createWebArchiveData(), isNotNull); }, skip: shouldSkipTest1); - testWidgets('save', (WidgetTester tester) async { + skippableTestWidgets('save', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/web_history.dart b/example/integration_test/in_app_webview/web_history.dart index 1cf278fc..bfe9d7c9 100644 --- a/example/integration_test/in_app_webview/web_history.dart +++ b/example/integration_test/in_app_webview/web_history.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void webHistory() { final shouldSkip = kIsWeb @@ -16,7 +9,7 @@ void webHistory() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - group('web history', () { + skippableGroup('web history', () { final shouldSkipTest1 = kIsWeb ? true : ![ @@ -25,7 +18,7 @@ void webHistory() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('get history list and go back/forward', + skippableTestWidgets('get history list and go back/forward', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); @@ -124,7 +117,8 @@ void webHistory() { final shouldSkipTest2 = !kIsWeb; - testWidgets('go back/forward on web platform', (WidgetTester tester) async { + skippableTestWidgets('go back/forward on web platform', + (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = @@ -183,7 +177,7 @@ void webHistory() { TargetPlatform.android, ].contains(defaultTargetPlatform); - testWidgets('clearHistory', (WidgetTester tester) async { + skippableTestWidgets('clearHistory', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = diff --git a/example/integration_test/in_app_webview/web_message.dart b/example/integration_test/in_app_webview/web_message.dart index 6c739265..2629e571 100644 --- a/example/integration_test/in_app_webview/web_message.dart +++ b/example/integration_test/in_app_webview/web_message.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void webMessage() { final shouldSkip = kIsWeb @@ -16,8 +9,8 @@ void webMessage() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - group('WebMessage', () { - testWidgets('WebMessageChannel', (WidgetTester tester) async { + skippableGroup('WebMessage', () { + skippableTestWidgets('WebMessageChannel', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer webMessageCompleter = Completer(); @@ -85,7 +78,7 @@ void webMessage() { expect(message, 'JavaScript To Native and back'); }); - testWidgets('WebMessageListener', (WidgetTester tester) async { + skippableTestWidgets('WebMessageListener', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/webview_asset_loader.dart b/example/integration_test/in_app_webview/webview_asset_loader.dart index a1307549..97f959c2 100644 --- a/example/integration_test/in_app_webview/webview_asset_loader.dart +++ b/example/integration_test/in_app_webview/webview_asset_loader.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void webViewAssetLoader() { final shouldSkip = kIsWeb @@ -14,7 +7,7 @@ void webViewAssetLoader() { TargetPlatform.android, ].contains(defaultTargetPlatform); - testWidgets('WebViewAssetLoader', (WidgetTester tester) async { + skippableTestWidgets('WebViewAssetLoader', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/in_app_webview/webview_windows.dart b/example/integration_test/in_app_webview/webview_windows.dart index 1208b39c..1db16a35 100644 --- a/example/integration_test/in_app_webview/webview_windows.dart +++ b/example/integration_test/in_app_webview/webview_windows.dart @@ -1,12 +1,4 @@ -import 'dart:async'; -import 'dart:convert'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void webViewWindows() { final shouldSkip = kIsWeb @@ -17,7 +9,7 @@ void webViewWindows() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - group("WebView Windows", () { + skippableGroup('WebView Windows', () { final shouldSkipTest1 = kIsWeb ? true : ![ @@ -26,7 +18,8 @@ void webViewWindows() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('onCreateWindow return false', (WidgetTester tester) async { + skippableTestWidgets('onCreateWindow return false', + (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); @@ -68,7 +61,8 @@ void webViewWindows() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('onCreateWindow return true', (WidgetTester tester) async { + skippableTestWidgets('onCreateWindow return true', + (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer onCreateWindowCompleter = Completer(); @@ -140,7 +134,8 @@ void webViewWindows() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('window.open() with target _blank opens in same window', + skippableTestWidgets( + 'window.open() with target _blank opens in same window', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); @@ -184,7 +179,8 @@ void webViewWindows() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); // on Android, for some reason, it works on an example app but not in this test - testWidgets('can open new window and go back', (WidgetTester tester) async { + skippableTestWidgets('can open new window and go back', + (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final StreamController pageLoads = @@ -236,7 +232,7 @@ void webViewWindows() { TargetPlatform.macOS, ].contains(defaultTargetPlatform); - testWidgets('javascript does not run in parent window', + skippableTestWidgets('javascript does not run in parent window', (WidgetTester tester) async { final String iframe = ''' @@ -311,7 +307,8 @@ void webViewWindows() { // final shouldSkipTest6 = !kIsWeb; final shouldSkipTest6 = true; // on Web, opening a new window during tests makes crash - testWidgets('onCreateWindow called on Web', (WidgetTester tester) async { + skippableTestWidgets('onCreateWindow called on Web', + (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer onCreateWindowCalled = Completer(); diff --git a/example/integration_test/proxy_controller/clear_and_set_proxy_override.dart b/example/integration_test/proxy_controller/clear_and_set_proxy_override.dart index 444f8ae4..349902e6 100644 --- a/example/integration_test/proxy_controller/clear_and_set_proxy_override.dart +++ b/example/integration_test/proxy_controller/clear_and_set_proxy_override.dart @@ -1,12 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; -import '../env.dart'; +part of 'main.dart'; void clearAndSetProxyOverride() { final shouldSkip = kIsWeb @@ -15,7 +7,8 @@ void clearAndSetProxyOverride() { TargetPlatform.android, ].contains(defaultTargetPlatform); - testWidgets('clear and set proxy override', (WidgetTester tester) async { + skippableTestWidgets('clear and set proxy override', + (WidgetTester tester) async { final Completer controllerCompleter = Completer(); final Completer pageLoaded = Completer(); diff --git a/example/integration_test/proxy_controller/main.dart b/example/integration_test/proxy_controller/main.dart index a7cc2908..e08eee2f 100644 --- a/example/integration_test/proxy_controller/main.dart +++ b/example/integration_test/proxy_controller/main.dart @@ -1,12 +1,19 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_test/flutter_test.dart'; +import 'dart:async'; -import 'clear_and_set_proxy_override.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; +import '../constants.dart'; +import '../env.dart'; +import '../util.dart'; + +part 'clear_and_set_proxy_override.dart'; void main() { final shouldSkip = kIsWeb; - group('Proxy Controller', () { + skippableGroup('Proxy Controller', () { clearAndSetProxyOverride(); }, skip: shouldSkip); } diff --git a/example/integration_test/service_worker_controller/main.dart b/example/integration_test/service_worker_controller/main.dart index 0d110c17..003e78db 100644 --- a/example/integration_test/service_worker_controller/main.dart +++ b/example/integration_test/service_worker_controller/main.dart @@ -1,8 +1,14 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_test/flutter_test.dart'; +import 'dart:async'; -import 'set_service_worker_client.dart'; -import 'should_intercept_request.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; +import 'package:flutter_test/flutter_test.dart'; +import '../constants.dart'; +import '../util.dart'; + +part 'set_service_worker_client.dart'; +part 'should_intercept_request.dart'; void main() { final shouldSkip = kIsWeb @@ -11,7 +17,7 @@ void main() { TargetPlatform.android, ].contains(defaultTargetPlatform); - group('Service Worker Controller', () { + skippableGroup('Service Worker Controller', () { shouldInterceptRequest(); setServiceWorkerClient(); }, skip: shouldSkip); diff --git a/example/integration_test/service_worker_controller/set_service_worker_client.dart b/example/integration_test/service_worker_controller/set_service_worker_client.dart index f17a57d8..30b8b4e4 100644 --- a/example/integration_test/service_worker_controller/set_service_worker_client.dart +++ b/example/integration_test/service_worker_controller/set_service_worker_client.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void setServiceWorkerClient() { final shouldSkip = kIsWeb @@ -14,7 +7,8 @@ void setServiceWorkerClient() { TargetPlatform.android, ].contains(defaultTargetPlatform); - testWidgets('setServiceWorkerClient to null', (WidgetTester tester) async { + skippableTestWidgets('setServiceWorkerClient to null', + (WidgetTester tester) async { final Completer pageLoaded = Completer(); var swAvailable = await WebViewFeature.isFeatureSupported( diff --git a/example/integration_test/service_worker_controller/should_intercept_request.dart b/example/integration_test/service_worker_controller/should_intercept_request.dart index f4d3bac1..319f6e96 100644 --- a/example/integration_test/service_worker_controller/should_intercept_request.dart +++ b/example/integration_test/service_worker_controller/should_intercept_request.dart @@ -1,11 +1,4 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import '../constants.dart'; +part of 'main.dart'; void shouldInterceptRequest() { final shouldSkip = kIsWeb @@ -14,7 +7,7 @@ void shouldInterceptRequest() { TargetPlatform.android, ].contains(defaultTargetPlatform); - testWidgets('shouldInterceptRequest', (WidgetTester tester) async { + skippableTestWidgets('shouldInterceptRequest', (WidgetTester tester) async { final Completer completer = Completer(); var swAvailable = await WebViewFeature.isFeatureSupported( diff --git a/example/integration_test/tracing_controller/main.dart b/example/integration_test/tracing_controller/main.dart index 4f89763a..fe6552e3 100644 --- a/example/integration_test/tracing_controller/main.dart +++ b/example/integration_test/tracing_controller/main.dart @@ -1,7 +1,15 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_test/flutter_test.dart'; +import 'dart:async'; +import 'dart:io'; -import 'start_and_stop.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path_provider/path_provider.dart'; +import '../constants.dart'; +import '../util.dart'; + +part 'start_and_stop.dart'; void main() { final shouldSkip = kIsWeb @@ -10,7 +18,7 @@ void main() { TargetPlatform.android, ].contains(defaultTargetPlatform); - group('Tracing Controller', () { + skippableGroup('Tracing Controller', () { startAndStop(); }, skip: shouldSkip); } diff --git a/example/integration_test/tracing_controller/start_and_stop.dart b/example/integration_test/tracing_controller/start_and_stop.dart index c7856361..e6869172 100644 --- a/example/integration_test/tracing_controller/start_and_stop.dart +++ b/example/integration_test/tracing_controller/start_and_stop.dart @@ -1,13 +1,4 @@ -import 'dart:async'; -import 'dart:io'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:path_provider/path_provider.dart'; - -import '../constants.dart'; +part of 'main.dart'; void startAndStop() { final shouldSkip = kIsWeb @@ -16,7 +7,7 @@ void startAndStop() { TargetPlatform.android, ].contains(defaultTargetPlatform); - testWidgets('start and stop', (WidgetTester tester) async { + skippableTestWidgets('start and stop', (WidgetTester tester) async { final Completer pageLoaded = Completer(); final tracingAvailable = await WebViewFeature.isFeatureSupported( diff --git a/example/integration_test/util.dart b/example/integration_test/util.dart index 3ad44249..ca1f24d2 100644 --- a/example/integration_test/util.dart +++ b/example/integration_test/util.dart @@ -19,6 +19,56 @@ class _NullOrEmpty extends Matcher { description.add('null or empty'); } +void skippableGroup(Object description, void Function() body, + {bool skip = false}) { + if (!skip) { + group(description.toString(), body, skip: skip); + } +} + +void skippableTest( + Object description, + dynamic Function() body, { + String? testOn, + Timeout? timeout = const Timeout(Duration(seconds: 60)), + bool skip = false, + dynamic tags, + Map? onPlatform, + int? retry, +}) { + if (!skip) { + test( + description.toString(), + body, + testOn: testOn, + timeout: timeout, + skip: skip, + onPlatform: onPlatform, + tags: tags, + retry: retry, + ); + } +} + +void skippableTestWidgets( + String description, + WidgetTesterCallback callback, { + bool skip = false, + Timeout? timeout = const Timeout(Duration(seconds: 60)), + bool semanticsEnabled = true, + TestVariant variant = const DefaultTestVariant(), + dynamic tags, +}) { + if (!skip) { + testWidgets(description, callback, + skip: skip, + timeout: timeout, + semanticsEnabled: semanticsEnabled, + variant: variant, + tags: tags); + } +} + class Foo { String? bar; String? baz; @@ -33,6 +83,7 @@ class Foo { class MyInAppBrowser extends InAppBrowser { final Completer browserCreated = Completer(); final Completer firstPageLoaded = Completer(); + final Completer browserClosed = Completer(); MyInAppBrowser( {int? windowId, UnmodifiableListView? initialUserScripts}) @@ -51,6 +102,13 @@ class MyInAppBrowser extends InAppBrowser { firstPageLoaded.complete(); } } + + @override + void onExit() { + if (!browserClosed.isCompleted) { + browserClosed.complete(); + } + } } class MyChromeSafariBrowser extends ChromeSafariBrowser { diff --git a/example/lib/in_app_browser_example.screen.dart b/example/lib/in_app_browser_example.screen.dart index 536afa6e..71cdcfd8 100755 --- a/example/lib/in_app_browser_example.screen.dart +++ b/example/lib/in_app_browser_example.screen.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'main.dart'; @@ -107,13 +108,24 @@ class _InAppBrowserExampleScreenState extends State { children: [ ElevatedButton( onPressed: () async { + widget.browser.addMenuItem(InAppBrowserMenuItem( + id: 2, + title: "Test 2", + icon: AndroidResource(name: "ic_menu_edit", defType: "drawable", defPackage: "android"), + iconColor: Colors.red, + onClick: () { + widget.browser.webViewController?.reload(); + }, + )); await widget.browser.openUrlRequest( urlRequest: URLRequest(url: WebUri("https://flutter.dev")), settings: InAppBrowserClassSettings( browserSettings: InAppBrowserSettings( toolbarTopBackgroundColor: Colors.blue, - presentationStyle: ModalPresentationStyle.POPOVER), + presentationStyle: ModalPresentationStyle.POPOVER, + hideCloseButton: true, + hideDefaultMenuItems: true), webViewSettings: InAppWebViewSettings( isInspectable: kDebugMode, useShouldOverrideUrlLoading: true, diff --git a/ios/Classes/InAppBrowser/InAppBrowserChannelDelegate.swift b/ios/Classes/InAppBrowser/InAppBrowserChannelDelegate.swift index 41593618..f97075c4 100644 --- a/ios/Classes/InAppBrowser/InAppBrowserChannelDelegate.swift +++ b/ios/Classes/InAppBrowser/InAppBrowserChannelDelegate.swift @@ -17,6 +17,13 @@ public class InAppBrowserChannelDelegate : ChannelDelegate { channel?.invokeMethod("onBrowserCreated", arguments: arguments) } + public func onMenuItemClicked(menuItem: InAppBrowserMenuItem) { + let arguments: [String: Any?] = [ + "id": menuItem.id + ] + channel?.invokeMethod("onMenuItemClicked", arguments: arguments) + } + public func onExit() { let arguments: [String: Any?] = [:] channel?.invokeMethod("onExit", arguments: arguments) diff --git a/ios/Classes/InAppBrowser/InAppBrowserManager.swift b/ios/Classes/InAppBrowser/InAppBrowserManager.swift index dce4c390..efd9aa1c 100755 --- a/ios/Classes/InAppBrowser/InAppBrowserManager.swift +++ b/ios/Classes/InAppBrowser/InAppBrowserManager.swift @@ -76,6 +76,7 @@ public class InAppBrowserManager: ChannelDelegate { let windowId = arguments["windowId"] as? Int64 let initialUserScripts = arguments["initialUserScripts"] as? [[String: Any]] let pullToRefreshInitialSettings = arguments["pullToRefreshSettings"] as! [String: Any?] + let menuItems = arguments["menuItems"] as! [[String: Any?]] let webViewController = prepareInAppBrowserWebViewController(settings: settings) @@ -90,6 +91,9 @@ public class InAppBrowserManager: ChannelDelegate { webViewController.windowId = windowId webViewController.initialUserScripts = initialUserScripts ?? [] webViewController.pullToRefreshInitialSettings = pullToRefreshInitialSettings + for menuItem in menuItems { + webViewController.menuItems.append(InAppBrowserMenuItem.fromMap(map: menuItem)!) + } presentViewController(webViewController: webViewController) } diff --git a/ios/Classes/InAppBrowser/InAppBrowserSettings.swift b/ios/Classes/InAppBrowser/InAppBrowserSettings.swift index 384acb4f..54d34244 100755 --- a/ios/Classes/InAppBrowser/InAppBrowserSettings.swift +++ b/ios/Classes/InAppBrowser/InAppBrowserSettings.swift @@ -27,6 +27,8 @@ public class InAppBrowserSettings: ISettings { var closeButtonColor: String? var presentationStyle = 0 //fullscreen var transitionStyle = 0 //crossDissolve + var hideCloseButton = false + var menuButtonColor: String? override init(){ super.init() @@ -40,6 +42,7 @@ public class InAppBrowserSettings: ISettings { realOptions["hideProgressBar"] = inAppBrowserWebViewController.progressBar.isHidden realOptions["closeButtonCaption"] = inAppBrowserWebViewController.closeButton.title realOptions["closeButtonColor"] = inAppBrowserWebViewController.closeButton.tintColor?.hexString + realOptions["menuButtonColor"] = inAppBrowserWebViewController.menuButton?.tintColor?.hexString if let navController = inAppBrowserWebViewController.navigationController { realOptions["hideToolbarTop"] = navController.navigationBar.isHidden realOptions["toolbarTopBackgroundColor"] = navController.navigationBar.backgroundColor?.hexString diff --git a/ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift b/ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift index 196291e7..bd475d03 100755 --- a/ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift +++ b/ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift @@ -20,6 +20,17 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega var shareButton: UIBarButtonItem! var searchBar: UISearchBar! var progressBar: UIProgressView! + var menuButton: UIBarButtonItem? + private var _menu: Any? + @available(iOS 13.0, *) + var menu: UIMenu? { + set { + _menu = newValue + } + get { + return _menu as? UIMenu + } + } var tmpWindow: UIWindow? var id: String = "" @@ -40,6 +51,7 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega var initialUserScripts: [[String: Any]] = [] var pullToRefreshInitialSettings: [String: Any?] = [:] var isHidden = false + var menuItems: [InAppBrowserMenuItem] = [] public override func loadView() { guard let plugin = plugin, let registrar = plugin.registrar else { @@ -235,6 +247,8 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega backButton = UIBarButtonItem(title: "\u{2039}", style: .plain, target: self, action: #selector(goBack)) backButton.isEnabled = false + toolbarItems = [backButton, spacer, forwardButton, spacer, shareButton, spacer, reloadButton] + for state: UIControl.State in [.normal, .disabled, .highlighted, .selected] { forwardButton.setTitleTextAttributes([ NSAttributedString.Key.font: UIFont.systemFont(ofSize: 50.0), @@ -246,35 +260,33 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega ], for: state) } - toolbarItems = [backButton, spacer, forwardButton, spacer, shareButton, spacer, reloadButton] - - if let browserOptions = browserSettings { - if !browserOptions.hideToolbarTop { + if let browserSettings = browserSettings { + if !browserSettings.hideToolbarTop { navigationController?.navigationBar.isHidden = false - if browserOptions.hideUrlBar { + if browserSettings.hideUrlBar { searchBar.isHidden = true } - if let bgColor = browserOptions.toolbarTopBackgroundColor, !bgColor.isEmpty { + if let bgColor = browserSettings.toolbarTopBackgroundColor, !bgColor.isEmpty { navigationController?.navigationBar.backgroundColor = UIColor(hexString: bgColor) } - if let barTintColor = browserOptions.toolbarTopBarTintColor, !barTintColor.isEmpty { + if let barTintColor = browserSettings.toolbarTopBarTintColor, !barTintColor.isEmpty { navigationController?.navigationBar.barTintColor = UIColor(hexString: barTintColor) } - if let tintColor = browserOptions.toolbarTopTintColor, !tintColor.isEmpty { + if let tintColor = browserSettings.toolbarTopTintColor, !tintColor.isEmpty { navigationController?.navigationBar.tintColor = UIColor(hexString: tintColor) } - navigationController?.navigationBar.isTranslucent = browserOptions.toolbarTopTranslucent + navigationController?.navigationBar.isTranslucent = browserSettings.toolbarTopTranslucent } else { navigationController?.navigationBar.isHidden = true } - if !browserOptions.hideToolbarBottom { + if !browserSettings.hideToolbarBottom { navigationController?.isToolbarHidden = false - if let bgColor = browserOptions.toolbarBottomBackgroundColor, !bgColor.isEmpty { + if let bgColor = browserSettings.toolbarBottomBackgroundColor, !bgColor.isEmpty { navigationController?.toolbar.barTintColor = UIColor(hexString: bgColor) } - if let tintColor = browserOptions.toolbarBottomTintColor, !tintColor.isEmpty { + if let tintColor = browserSettings.toolbarBottomTintColor, !tintColor.isEmpty { navigationController?.toolbar.tintColor = UIColor(hexString: tintColor) } navigationController?.toolbar.isTranslucent = false @@ -283,22 +295,52 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega navigationController?.isToolbarHidden = true } - if let closeButtonCaption = browserOptions.closeButtonCaption, !closeButtonCaption.isEmpty { + if let closeButtonCaption = browserSettings.closeButtonCaption, !closeButtonCaption.isEmpty { closeButton = UIBarButtonItem(title: closeButtonCaption, style: .plain, target: self, action: #selector(close)) } else { setDefaultCloseButton() } - if let closeButtonColor = browserOptions.closeButtonColor, !closeButtonColor.isEmpty { + if let closeButtonColor = browserSettings.closeButtonColor, !closeButtonColor.isEmpty { closeButton.tintColor = UIColor(hexString: closeButtonColor) } - if browserOptions.hideProgressBar { + if browserSettings.hideProgressBar { progressBar.isHidden = true } + + navigationItem.rightBarButtonItems = [] + + if !browserSettings.hideCloseButton { + navigationItem.rightBarButtonItems = [closeButton] + } + + if #available(iOS 14.0, *), !menuItems.isEmpty { + var uiActions: [UIAction] = [] + menuItems = menuItems.sorted(by: {$0.order ?? 0 < $1.order ?? 0}) + for menuItem in menuItems { + let uiAction = UIAction(title: menuItem.title, image: menuItem.icon, handler: {_ in + self.channelDelegate?.onMenuItemClicked(menuItem: menuItem) + }) + if !menuItem.showAsAction { + uiActions.append(uiAction) + } else { + navigationItem.rightBarButtonItems?.append( + UIBarButtonItem(primaryAction: uiAction) + ) + } + } + if !uiActions.isEmpty { + menu = UIMenu(title: "", options: .displayInline, children: uiActions) + menuButton = UIBarButtonItem(image: UIImage(systemName: "ellipsis.circle"), menu: menu) + if let menuButtonColor = browserSettings.menuButtonColor, !menuButtonColor.isEmpty { + menuButton?.tintColor = UIColor(hexString: menuButtonColor) + } + let index = browserSettings.hideCloseButton ? 0 : 1 + navigationItem.rightBarButtonItems?.insert(menuButton!, at: index) + } + } } - - navigationItem.rightBarButtonItem = closeButton } func setDefaultCloseButton() { @@ -306,11 +348,11 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega closeButton.target = nil closeButton.action = nil } + var barButtonSystemItem = UIBarButtonItem.SystemItem.cancel if #available(iOS 13.0, *) { - closeButton = UIBarButtonItem(barButtonSystemItem: .close, target: self, action: #selector(close)) - } else { - closeButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(close)) + barButtonSystemItem = UIBarButtonItem.SystemItem.close } + closeButton = UIBarButtonItem(barButtonSystemItem: barButtonSystemItem, target: self, action: #selector(close)) } public func didChangeTitle(title: String?) { @@ -541,6 +583,14 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega } } + if newSettingsMap["hideCloseButton"] != nil, browserSettings?.hideCloseButton != newSettings.hideCloseButton { + if !newSettings.hideCloseButton { + navigationItem.rightBarButtonItems = [closeButton] + } else { + navigationItem.rightBarButtonItems = [] + } + } + if newSettingsMap["presentationStyle"] != nil, browserSettings?.presentationStyle != newSettings.presentationStyle { navigationController?.modalPresentationStyle = UIModalPresentationStyle(rawValue: newSettings.presentationStyle)! } @@ -553,6 +603,14 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega progressBar.isHidden = newSettings.hideProgressBar } + if newSettingsMap["menuButtonColor"] != nil, browserSettings?.menuButtonColor != newSettings.menuButtonColor { + if let tintColor = newSettings.menuButtonColor, !tintColor.isEmpty { + menuButton?.tintColor = UIColor(hexString: tintColor) + } else { + menuButton?.tintColor = nil + } + } + browserSettings = newSettings webViewSettings = newInAppWebViewSettings } @@ -584,6 +642,7 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega backButton.target = nil reloadButton.target = nil shareButton.target = nil + menuButton?.target = nil plugin = nil } diff --git a/ios/Classes/Types/InAppBrowserMenuItem.swift b/ios/Classes/Types/InAppBrowserMenuItem.swift new file mode 100644 index 00000000..8a603daa --- /dev/null +++ b/ios/Classes/Types/InAppBrowserMenuItem.swift @@ -0,0 +1,48 @@ +// +// InAppBrowserMenuItem.swift +// flutter_inappwebview +// +// Created by Lorenzo Pichilli on 21/05/23. +// + +import Foundation + +public class InAppBrowserMenuItem: NSObject { + var id: Int64 + var title: String + var order: Int64? + var icon: UIImage? + var iconColor: UIColor? + var showAsAction = false + + public init(id: Int64, title: String, order: Int64?, icon: UIImage?, iconColor: UIColor?, showAsAction: Bool) { + self.id = id + self.title = title + self.order = order + self.icon = icon + self.iconColor = iconColor + self.showAsAction = showAsAction + if #available(iOS 13.0, *), let icon = icon, let iconColor = iconColor { + icon.withTintColor(iconColor) + } + } + + public static func fromMap(map: [String:Any?]?) -> InAppBrowserMenuItem? { + guard let map = map else { + return nil + } + let id = map["id"] as! Int64 + let title = map["title"] as! String + let order = map["order"] as? Int64 + var icon = UIImage.fromMap(map: map["icon"] as? [String : Any?]) + if let data = map["icon"] as? FlutterStandardTypedData { + icon = UIImage(data: data.data) + } + var iconColor: UIColor? = nil + if let hexString = map["iconColor"] as? String { + iconColor = UIColor(hexString: hexString) + } + let showAsAction = map["showAsAction"] as! Bool + return InAppBrowserMenuItem(id: id, title: title, order: order, icon: icon, iconColor: iconColor, showAsAction: showAsAction) + } +} diff --git a/lib/src/android/webview_asset_loader.g.dart b/lib/src/android/webview_asset_loader.g.dart index e95819fd..f3c8df9c 100644 --- a/lib/src/android/webview_asset_loader.g.dart +++ b/lib/src/android/webview_asset_loader.g.dart @@ -133,8 +133,8 @@ abstract class PathHandler { ///Converts instance to a map. Map toMap() { return { - ..._toMapMergeWith(), "path": path, + ..._toMapMergeWith(), }; } @@ -184,8 +184,8 @@ class AssetsPathHandler extends PathHandler { ///Converts instance to a map. Map toMap() { return { - ..._toMapMergeWith(), "path": path, + ..._toMapMergeWith(), }; } @@ -235,8 +235,8 @@ class ResourcesPathHandler extends PathHandler { ///Converts instance to a map. Map toMap() { return { - ..._toMapMergeWith(), "path": path, + ..._toMapMergeWith(), }; } @@ -294,9 +294,9 @@ class InternalStoragePathHandler extends PathHandler { ///Converts instance to a map. Map toMap() { return { - ..._toMapMergeWith(), "path": path, "directory": directory, + ..._toMapMergeWith(), }; } diff --git a/lib/src/chrome_safari_browser/chrome_safari_action_button.dart b/lib/src/chrome_safari_browser/chrome_safari_action_button.dart new file mode 100644 index 00000000..89cc03cd --- /dev/null +++ b/lib/src/chrome_safari_browser/chrome_safari_action_button.dart @@ -0,0 +1,43 @@ +import 'dart:typed_data'; + +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +import 'chrome_safari_browser.dart'; +import '../web_uri.dart'; + +part 'chrome_safari_action_button.g.dart'; + +///Class that represents a custom action button for a [ChromeSafariBrowser] instance. +@SupportedPlatforms(platforms: [ + AndroidPlatform(note: 'Not available in an Android Trusted Web Activity.'), +]) +@ExchangeableObject() +class ChromeSafariBrowserActionButton_ { + ///The action button id. It should be different from the [ChromeSafariBrowserMenuItem.id]. + int id; + + ///The icon byte data. + Uint8List icon; + + ///The description for the button. To be used for accessibility. + String description; + + ///Whether the action button should be tinted. + bool shouldTint; + + ///Use onClick instead. + @Deprecated("Use onClick instead") + void Function(String url, String title)? action; + + ///Callback function to be invoked when the action button is clicked + void Function(WebUri? url, String title)? onClick; + + @ExchangeableObjectConstructor() + ChromeSafariBrowserActionButton_( + {required this.id, + required this.icon, + required this.description, + @Deprecated("Use onClick instead") this.action, + this.onClick, + this.shouldTint = false}); +} diff --git a/lib/src/chrome_safari_browser/chrome_safari_action_button.g.dart b/lib/src/chrome_safari_browser/chrome_safari_action_button.g.dart new file mode 100644 index 00000000..7d9e3c23 --- /dev/null +++ b/lib/src/chrome_safari_browser/chrome_safari_action_button.g.dart @@ -0,0 +1,81 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'chrome_safari_action_button.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///Class that represents a custom action button for a [ChromeSafariBrowser] instance. +/// +///**NOTE for Android native WebView**: Not available in an Android Trusted Web Activity. +/// +///**Supported Platforms/Implementations**: +///- Android native WebView +class ChromeSafariBrowserActionButton { + ///Use onClick instead. + @Deprecated('Use onClick instead') + void Function(String, String)? action; + + ///The description for the button. To be used for accessibility. + String description; + + ///The icon byte data. + Uint8List icon; + + ///The action button id. It should be different from the [ChromeSafariBrowserMenuItem.id]. + int id; + + ///Callback function to be invoked when the action button is clicked + void Function(WebUri?, String)? onClick; + + ///Whether the action button should be tinted. + bool shouldTint; + + /// + ///**NOTE for Android native WebView**: Not available in an Android Trusted Web Activity. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ChromeSafariBrowserActionButton( + {required this.id, + required this.icon, + required this.description, + @Deprecated("Use onClick instead") this.action, + this.onClick, + this.shouldTint = false}); + + ///Gets a possible [ChromeSafariBrowserActionButton] instance from a [Map] value. + static ChromeSafariBrowserActionButton? fromMap(Map? map) { + if (map == null) { + return null; + } + final instance = ChromeSafariBrowserActionButton( + description: map['description'], + icon: map['icon'], + id: map['id'], + ); + instance.shouldTint = map['shouldTint']; + return instance; + } + + ///Converts instance to a map. + Map toMap() { + return { + "description": description, + "icon": icon, + "id": id, + "shouldTint": shouldTint, + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'ChromeSafariBrowserActionButton{description: $description, icon: $icon, id: $id, shouldTint: $shouldTint}'; + } +} diff --git a/lib/src/chrome_safari_browser/chrome_safari_browser.dart b/lib/src/chrome_safari_browser/chrome_safari_browser.dart index 4d30e864..cb55e224 100755 --- a/lib/src/chrome_safari_browser/chrome_safari_browser.dart +++ b/lib/src/chrome_safari_browser/chrome_safari_browser.dart @@ -4,16 +4,17 @@ import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; -import '../types/android_resource.dart'; import '../types/custom_tabs_navigation_event_type.dart'; import '../types/custom_tabs_relation_type.dart'; import '../types/prewarming_token.dart'; -import '../types/ui_image.dart'; import '../util.dart'; import '../debug_logging_settings.dart'; import '../web_uri.dart'; import 'chrome_safari_browser_settings.dart'; +import 'chrome_safari_action_button.dart'; +import 'chrome_safari_browser_menu_item.dart'; +import 'chrome_safari_browser_secondary_toolbar.dart'; ///This class uses native [Chrome Custom Tabs](https://developer.android.com/reference/android/support/customtabs/package-summary) on Android ///and [SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller) on iOS. @@ -547,171 +548,3 @@ class ChromeSafariBrowser { _channel = null; } } - -///Class that represents a custom action button for a [ChromeSafariBrowser] instance. -/// -///**NOTE**: Not available in an Android Trusted Web Activity. -/// -///**Supported Platforms/Implementations**: -///- Android -class ChromeSafariBrowserActionButton { - ///The action button id. It should be different from the [ChromeSafariBrowserMenuItem.id]. - int id; - - ///The icon byte data. - Uint8List icon; - - ///The description for the button. To be used for accessibility. - String description; - - ///Whether the action button should be tinted. - bool shouldTint; - - ///Use onClick instead. - @Deprecated("Use onClick instead") - void Function(String url, String title)? action; - - ///Callback function to be invoked when the action button is clicked - void Function(WebUri? url, String title)? onClick; - - ChromeSafariBrowserActionButton( - {required this.id, - required this.icon, - required this.description, - @Deprecated("Use onClick instead") this.action, - this.onClick, - this.shouldTint = false}); - - Map toMap() { - return { - "id": id, - "icon": icon, - "description": description, - "shouldTint": shouldTint - }; - } - - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } -} - -///Class that represents a custom menu item for a [ChromeSafariBrowser] instance. -/// -///**NOTE**: Not available in an Android Trusted Web Activity. -/// -///**Supported Platforms/Implementations**: -///- Android -///- iOS -class ChromeSafariBrowserMenuItem { - ///The menu item id. It should be different from [ChromeSafariBrowserActionButton.id]. - int id; - - ///The label of the menu item. - String label; - - ///Item image. - UIImage? image; - - ///Use onClick instead. - @Deprecated("Use onClick instead") - void Function(String url, String title)? action; - - ///Callback function to be invoked when the menu item is clicked - void Function(WebUri? url, String title)? onClick; - - ChromeSafariBrowserMenuItem( - {required this.id, - required this.label, - this.image, - @Deprecated("Use onClick instead") this.action, - this.onClick}); - - Map toMap() { - return {"id": id, "label": label, "image": image?.toMap()}; - } - - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } -} - -///Class that represents the [RemoteViews](https://developer.android.com/reference/android/widget/RemoteViews.html) -///that will be shown on the secondary toolbar of a custom tab. -/// -///This class describes a view hierarchy that can be displayed in another process. -///The hierarchy is inflated from an Android layout resource file. -/// -///RemoteViews has limited to support to Android layouts. -///Check the [RemoteViews Official API](https://developer.android.com/reference/android/widget/RemoteViews.html) for more details. -/// -///**NOTE**: Not available in an Android Trusted Web Activity. -/// -///**Supported Platforms/Implementations**: -///- Android -class ChromeSafariBrowserSecondaryToolbar { - ///The android layout resource. - AndroidResource layout; - - ///The IDs of clickable views. The `onClick` event of these views will be handled by custom tabs. - List clickableIDs; - - ChromeSafariBrowserSecondaryToolbar( - {required this.layout, this.clickableIDs = const []}); - - Map toMap() { - return { - "layout": layout.toMap(), - "clickableIDs": clickableIDs.map((e) => e.toMap()).toList() - }; - } - - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } -} - -///Class that represents a clickable ID item of the secondary toolbar for a [ChromeSafariBrowser] instance. -/// -///**NOTE**: Not available in an Android Trusted Web Activity. -/// -///**Supported Platforms/Implementations**: -///- Android -class ChromeSafariBrowserSecondaryToolbarClickableID { - ///The android id resource - AndroidResource id; - - ///Callback function to be invoked when the item is clicked - void Function(WebUri? url)? onClick; - - ChromeSafariBrowserSecondaryToolbarClickableID( - {required this.id, this.onClick}); - - Map toMap() { - return {"id": id.toMap()}; - } - - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } -} diff --git a/lib/src/chrome_safari_browser/chrome_safari_browser_menu_item.dart b/lib/src/chrome_safari_browser/chrome_safari_browser_menu_item.dart new file mode 100644 index 00000000..a5ac4599 --- /dev/null +++ b/lib/src/chrome_safari_browser/chrome_safari_browser_menu_item.dart @@ -0,0 +1,39 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +import '../types/ui_image.dart'; +import 'chrome_safari_browser.dart'; +import '../web_uri.dart'; + +part 'chrome_safari_browser_menu_item.g.dart'; + +///Class that represents a custom menu item for a [ChromeSafariBrowser] instance. +@SupportedPlatforms(platforms: [ + AndroidPlatform(note: 'Not available in an Android Trusted Web Activity.'), + IOSPlatform() +]) +@ExchangeableObject() +class ChromeSafariBrowserMenuItem_ { + ///The menu item id. It should be different from [ChromeSafariBrowserActionButton.id]. + int id; + + ///The label of the menu item. + String label; + + ///Item image. + UIImage_? image; + + ///Use onClick instead. + @Deprecated("Use onClick instead") + void Function(String url, String title)? action; + + ///Callback function to be invoked when the menu item is clicked + void Function(WebUri? url, String title)? onClick; + + @ExchangeableObjectConstructor() + ChromeSafariBrowserMenuItem_( + {required this.id, + required this.label, + this.image, + @Deprecated("Use onClick instead") this.action, + this.onClick}); +} diff --git a/lib/src/chrome_safari_browser/chrome_safari_browser_menu_item.g.dart b/lib/src/chrome_safari_browser/chrome_safari_browser_menu_item.g.dart new file mode 100644 index 00000000..014ad3de --- /dev/null +++ b/lib/src/chrome_safari_browser/chrome_safari_browser_menu_item.g.dart @@ -0,0 +1,77 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'chrome_safari_browser_menu_item.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///Class that represents a custom menu item for a [ChromeSafariBrowser] instance. +/// +///**NOTE for Android native WebView**: Not available in an Android Trusted Web Activity. +/// +///**Supported Platforms/Implementations**: +///- Android native WebView +///- iOS +class ChromeSafariBrowserMenuItem { + ///Use onClick instead. + @Deprecated('Use onClick instead') + void Function(String, String)? action; + + ///The menu item id. It should be different from [ChromeSafariBrowserActionButton.id]. + int id; + + ///Item image. + UIImage? image; + + ///The label of the menu item. + String label; + + ///Callback function to be invoked when the menu item is clicked + void Function(WebUri?, String)? onClick; + + /// + ///**NOTE for Android native WebView**: Not available in an Android Trusted Web Activity. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS + ChromeSafariBrowserMenuItem( + {required this.id, + required this.label, + this.image, + @Deprecated("Use onClick instead") this.action, + this.onClick}); + + ///Gets a possible [ChromeSafariBrowserMenuItem] instance from a [Map] value. + static ChromeSafariBrowserMenuItem? fromMap(Map? map) { + if (map == null) { + return null; + } + final instance = ChromeSafariBrowserMenuItem( + id: map['id'], + image: UIImage.fromMap(map['image']?.cast()), + label: map['label'], + ); + return instance; + } + + ///Converts instance to a map. + Map toMap() { + return { + "id": id, + "image": image?.toMap(), + "label": label, + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'ChromeSafariBrowserMenuItem{id: $id, image: $image, label: $label}'; + } +} diff --git a/lib/src/chrome_safari_browser/chrome_safari_browser_secondary_toolbar.dart b/lib/src/chrome_safari_browser/chrome_safari_browser_secondary_toolbar.dart new file mode 100644 index 00000000..9dfe02c8 --- /dev/null +++ b/lib/src/chrome_safari_browser/chrome_safari_browser_secondary_toolbar.dart @@ -0,0 +1,46 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +import '../types/android_resource.dart'; +import '../web_uri.dart'; +import 'chrome_safari_browser.dart'; + +part 'chrome_safari_browser_secondary_toolbar.g.dart'; + +///Class that represents the [RemoteViews](https://developer.android.com/reference/android/widget/RemoteViews.html) +///that will be shown on the secondary toolbar of a custom tab. +/// +///This class describes a view hierarchy that can be displayed in another process. +///The hierarchy is inflated from an Android layout resource file. +/// +///RemoteViews has limited to support to Android layouts. +///Check the [RemoteViews Official API](https://developer.android.com/reference/android/widget/RemoteViews.html) for more details. +@SupportedPlatforms(platforms: [ + AndroidPlatform(note: 'Not available in an Android Trusted Web Activity.') +]) +@ExchangeableObject() +class ChromeSafariBrowserSecondaryToolbar_ { + ///The android layout resource. + AndroidResource_ layout; + + ///The IDs of clickable views. The `onClick` event of these views will be handled by custom tabs. + List clickableIDs; + + ChromeSafariBrowserSecondaryToolbar_( + {required this.layout, this.clickableIDs = const []}); +} + +///Class that represents a clickable ID item of the secondary toolbar for a [ChromeSafariBrowser] instance. +@SupportedPlatforms(platforms: [ + AndroidPlatform(note: 'Not available in an Android Trusted Web Activity.') +]) +@ExchangeableObject() +class ChromeSafariBrowserSecondaryToolbarClickableID_ { + ///The android id resource + AndroidResource_ id; + + ///Callback function to be invoked when the item is clicked + void Function(WebUri? url)? onClick; + + ChromeSafariBrowserSecondaryToolbarClickableID_( + {required this.id, this.onClick}); +} diff --git a/lib/src/chrome_safari_browser/chrome_safari_browser_secondary_toolbar.g.dart b/lib/src/chrome_safari_browser/chrome_safari_browser_secondary_toolbar.g.dart new file mode 100644 index 00000000..20185c2f --- /dev/null +++ b/lib/src/chrome_safari_browser/chrome_safari_browser_secondary_toolbar.g.dart @@ -0,0 +1,122 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'chrome_safari_browser_secondary_toolbar.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///Class that represents the [RemoteViews](https://developer.android.com/reference/android/widget/RemoteViews.html) +///that will be shown on the secondary toolbar of a custom tab. +/// +///This class describes a view hierarchy that can be displayed in another process. +///The hierarchy is inflated from an Android layout resource file. +/// +///RemoteViews has limited to support to Android layouts. +///Check the [RemoteViews Official API](https://developer.android.com/reference/android/widget/RemoteViews.html) for more details. +/// +///**NOTE for Android native WebView**: Not available in an Android Trusted Web Activity. +/// +///**Supported Platforms/Implementations**: +///- Android native WebView +class ChromeSafariBrowserSecondaryToolbar { + ///The IDs of clickable views. The `onClick` event of these views will be handled by custom tabs. + List clickableIDs; + + ///The android layout resource. + AndroidResource layout; + + /// + ///**NOTE for Android native WebView**: Not available in an Android Trusted Web Activity. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ChromeSafariBrowserSecondaryToolbar( + {this.clickableIDs = const [], required this.layout}); + + ///Gets a possible [ChromeSafariBrowserSecondaryToolbar] instance from a [Map] value. + static ChromeSafariBrowserSecondaryToolbar? fromMap( + Map? map) { + if (map == null) { + return null; + } + final instance = ChromeSafariBrowserSecondaryToolbar( + layout: AndroidResource.fromMap(map['layout']?.cast())!, + ); + instance.clickableIDs = + List.from( + map['clickableIDs'].map((e) => + ChromeSafariBrowserSecondaryToolbarClickableID.fromMap( + e?.cast())!)); + return instance; + } + + ///Converts instance to a map. + Map toMap() { + return { + "clickableIDs": clickableIDs.map((e) => e.toMap()).toList(), + "layout": layout.toMap(), + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'ChromeSafariBrowserSecondaryToolbar{clickableIDs: $clickableIDs, layout: $layout}'; + } +} + +///Class that represents a clickable ID item of the secondary toolbar for a [ChromeSafariBrowser] instance. +/// +///**NOTE for Android native WebView**: Not available in an Android Trusted Web Activity. +/// +///**Supported Platforms/Implementations**: +///- Android native WebView +class ChromeSafariBrowserSecondaryToolbarClickableID { + ///The android id resource + AndroidResource id; + + ///Callback function to be invoked when the item is clicked + void Function(WebUri?)? onClick; + + /// + ///**NOTE for Android native WebView**: Not available in an Android Trusted Web Activity. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ChromeSafariBrowserSecondaryToolbarClickableID( + {required this.id, this.onClick}); + + ///Gets a possible [ChromeSafariBrowserSecondaryToolbarClickableID] instance from a [Map] value. + static ChromeSafariBrowserSecondaryToolbarClickableID? fromMap( + Map? map) { + if (map == null) { + return null; + } + final instance = ChromeSafariBrowserSecondaryToolbarClickableID( + id: AndroidResource.fromMap(map['id']?.cast())!, + ); + return instance; + } + + ///Converts instance to a map. + Map toMap() { + return { + "id": id.toMap(), + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'ChromeSafariBrowserSecondaryToolbarClickableID{id: $id}'; + } +} diff --git a/lib/src/chrome_safari_browser/main.dart b/lib/src/chrome_safari_browser/main.dart index 9d23040d..d21cf364 100644 --- a/lib/src/chrome_safari_browser/main.dart +++ b/lib/src/chrome_safari_browser/main.dart @@ -6,3 +6,9 @@ export 'chrome_safari_browser_settings.dart' ChromeSafariBrowserClassOptions; export 'android/main.dart'; export 'apple/main.dart'; +export 'chrome_safari_action_button.dart' show ChromeSafariBrowserActionButton; +export 'chrome_safari_browser_menu_item.dart' show ChromeSafariBrowserMenuItem; +export 'chrome_safari_browser_secondary_toolbar.dart' + show + ChromeSafariBrowserSecondaryToolbar, + ChromeSafariBrowserSecondaryToolbarClickableID; diff --git a/lib/src/context_menu.dart b/lib/src/context_menu.dart deleted file mode 100644 index 0d713ca1..00000000 --- a/lib/src/context_menu.dart +++ /dev/null @@ -1,168 +0,0 @@ -import 'in_app_webview/webview.dart'; -import 'types/main.dart'; -import 'util.dart'; - -///Class that represents the WebView context menu. It used by [WebView.contextMenu]. -/// -///**NOTE**: To make it work properly on Android, JavaScript should be enabled! -/// -///**Supported Platforms/Implementations**: -///- Android native WebView -///- iOS -class ContextMenu { - ///Event fired when the context menu for this WebView is being built. - /// - ///[hitTestResult] represents the hit result for hitting an HTML elements. - final void Function(InAppWebViewHitTestResult hitTestResult)? - onCreateContextMenu; - - ///Event fired when the context menu for this WebView is being hidden. - final void Function()? onHideContextMenu; - - ///Event fired when a context menu item has been clicked. - /// - ///[contextMenuItemClicked] represents the [ContextMenuItem] clicked. - final void Function(ContextMenuItem contextMenuItemClicked)? - onContextMenuActionItemClicked; - - ///Use [settings] instead - @Deprecated("Use settings instead") - final ContextMenuOptions? options; - - ///Context menu settings. - final ContextMenuSettings? settings; - - ///List of the custom [ContextMenuItem]. - final List menuItems; - - ContextMenu( - {this.menuItems = const [], - this.onCreateContextMenu, - this.onHideContextMenu, - @Deprecated("Use settings instead") this.options, - this.settings, - this.onContextMenuActionItemClicked}); - - Map toMap() { - return { - "menuItems": menuItems.map((menuItem) => menuItem.toMap()).toList(), - // ignore: deprecated_member_use_from_same_package - "settings": settings?.toMap() ?? options?.toMap() - }; - } - - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } -} - -///Class that represent an item of the [ContextMenu]. -class ContextMenuItem { - ///Use [id] instead. - @Deprecated("Use id instead") - int? androidId; - - ///Use [id] instead. - @Deprecated("Use id instead") - String? iosId; - - ///Menu item ID. It cannot be `null` and it can be a [String] or an [int]. - /// - ///**NOTE for Android**: it must be an [int] value. - dynamic id; - - ///Menu item title. - String title; - - ///Menu item action that will be called when an user clicks on it. - Function()? action; - - ContextMenuItem( - {this.id, - @Deprecated("Use id instead") this.androidId, - @Deprecated("Use id instead") this.iosId, - required this.title, - this.action}) { - if (Util.isAndroid) { - // ignore: deprecated_member_use_from_same_package - this.id = this.id ?? this.androidId; - assert(this.id is int); - } else if (Util.isIOS) { - // ignore: deprecated_member_use_from_same_package - this.id = this.id ?? this.iosId; - } - assert(this.id != null && (this.id is int || this.id is String)); - } - - Map toMap() { - return { - "id": id, - // ignore: deprecated_member_use_from_same_package - "androidId": androidId, - // ignore: deprecated_member_use_from_same_package - "iosId": iosId, - "title": title - }; - } - - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } -} - -///Class that represents available settings used by [ContextMenu]. -class ContextMenuSettings { - ///Whether all the default system context menu items should be hidden or not. The default value is `false`. - bool hideDefaultSystemContextMenuItems; - - ContextMenuSettings({this.hideDefaultSystemContextMenuItems = false}); - - Map toMap() { - return { - "hideDefaultSystemContextMenuItems": hideDefaultSystemContextMenuItems - }; - } - - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } -} - -///Use [ContextMenuSettings] instead. -@Deprecated("Use ContextMenuSettings instead") -class ContextMenuOptions { - ///Whether all the default system context menu items should be hidden or not. The default value is `false`. - bool hideDefaultSystemContextMenuItems; - - ContextMenuOptions({this.hideDefaultSystemContextMenuItems = false}); - - Map toMap() { - return { - "hideDefaultSystemContextMenuItems": hideDefaultSystemContextMenuItems - }; - } - - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } -} diff --git a/lib/src/context_menu/context_menu.dart b/lib/src/context_menu/context_menu.dart new file mode 100644 index 00000000..9af6cf0b --- /dev/null +++ b/lib/src/context_menu/context_menu.dart @@ -0,0 +1,61 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +import '../in_app_webview/webview.dart'; +import '../types/in_app_webview_hit_test_result.dart'; +import 'context_menu_item.dart'; +import 'context_menu_settings.dart'; + +part 'context_menu.g.dart'; + +///Class that represents the WebView context menu. It used by [WebView.contextMenu]. +@SupportedPlatforms(platforms: [ + AndroidPlatform( + note: + 'To make it work properly on Android, JavaScript should be enabled!'), + IOSPlatform() +]) +@ExchangeableObject() +class ContextMenu_ { + ///Event fired when the context menu for this WebView is being built. + /// + ///[hitTestResult] represents the hit result for hitting an HTML elements. + final void Function(InAppWebViewHitTestResult_ hitTestResult)? + onCreateContextMenu; + + ///Event fired when the context menu for this WebView is being hidden. + final void Function()? onHideContextMenu; + + ///Event fired when a context menu item has been clicked. + /// + ///[contextMenuItemClicked] represents the [ContextMenuItem] clicked. + final void Function(ContextMenuItem_ contextMenuItemClicked)? + onContextMenuActionItemClicked; + + ///Use [settings] instead + @Deprecated("Use settings instead") + final ContextMenuOptions? options; + + ///Context menu settings. + final ContextMenuSettings_? settings; + + ///List of the custom [ContextMenuItem]. + final List menuItems; + + @ExchangeableObjectConstructor() + ContextMenu_( + {this.menuItems = const [], + this.onCreateContextMenu, + this.onHideContextMenu, + @Deprecated("Use settings instead") this.options, + this.settings, + this.onContextMenuActionItemClicked}); + + @ExchangeableObjectMethod(toMapMergeWith: true) + // ignore: unused_element + Map _toMapMergeWith() { + return { + "settings": + (settings as ContextMenuSettings?)?.toMap() ?? options?.toMap() + }; + } +} diff --git a/lib/src/context_menu/context_menu.g.dart b/lib/src/context_menu/context_menu.g.dart new file mode 100644 index 00000000..01e57939 --- /dev/null +++ b/lib/src/context_menu/context_menu.g.dart @@ -0,0 +1,95 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'context_menu.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///Class that represents the WebView context menu. It used by [WebView.contextMenu]. +/// +///**NOTE for Android native WebView**: To make it work properly on Android, JavaScript should be enabled! +/// +///**Supported Platforms/Implementations**: +///- Android native WebView +///- iOS +class ContextMenu { + ///List of the custom [ContextMenuItem]. + final List menuItems; + + ///Event fired when a context menu item has been clicked. + /// + ///[contextMenuItemClicked] represents the [ContextMenuItem] clicked. + final void Function(ContextMenuItem)? onContextMenuActionItemClicked; + + ///Event fired when the context menu for this WebView is being built. + /// + ///[hitTestResult] represents the hit result for hitting an HTML elements. + final void Function(InAppWebViewHitTestResult)? onCreateContextMenu; + + ///Event fired when the context menu for this WebView is being hidden. + final void Function()? onHideContextMenu; + + ///Use [settings] instead + @Deprecated('Use settings instead') + final ContextMenuOptions? options; + + ///Context menu settings. + final ContextMenuSettings? settings; + + /// + ///**NOTE for Android native WebView**: To make it work properly on Android, JavaScript should be enabled! + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS + ContextMenu( + {this.menuItems = const [], + this.onCreateContextMenu, + this.onHideContextMenu, + @Deprecated("Use settings instead") this.options, + this.settings, + this.onContextMenuActionItemClicked}); + + ///Gets a possible [ContextMenu] instance from a [Map] value. + static ContextMenu? fromMap(Map? map) { + if (map == null) { + return null; + } + final instance = ContextMenu( + menuItems: List.from(map['menuItems'] + .map((e) => ContextMenuItem.fromMap(e?.cast())!)), + options: map['settings'], + settings: + ContextMenuSettings.fromMap(map['settings']?.cast()), + ); + return instance; + } + + @ExchangeableObjectMethod(toMapMergeWith: true) + Map _toMapMergeWith() { + return { + "settings": + (settings as ContextMenuSettings?)?.toMap() ?? options?.toMap() + }; + } + + ///Converts instance to a map. + Map toMap() { + return { + "menuItems": menuItems.map((e) => e.toMap()).toList(), + "settings": settings?.toMap(), + ..._toMapMergeWith(), + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'ContextMenu{menuItems: $menuItems, settings: $settings}'; + } +} diff --git a/lib/src/context_menu/context_menu_item.dart b/lib/src/context_menu/context_menu_item.dart new file mode 100644 index 00000000..ec7a29bc --- /dev/null +++ b/lib/src/context_menu/context_menu_item.dart @@ -0,0 +1,53 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +import 'context_menu.dart'; +import '../util.dart'; + +part 'context_menu_item.g.dart'; + +///Class that represent an item of the [ContextMenu]. +@ExchangeableObject() +class ContextMenuItem_ { + ///Use [id] instead. + @Deprecated("Use id instead") + int? androidId; + + ///Use [id] instead. + @Deprecated("Use id instead") + String? iosId; + + ///Menu item ID. It cannot be `null` and it can be a [String] or an [int]. + /// + ///**NOTE for Android**: it must be an [int] value. + dynamic id; + + ///Menu item title. + String title; + + ///Menu item action that will be called when an user clicks on it. + Function()? action; + + @ExchangeableObjectConstructor() + ContextMenuItem_( + {this.id, + @Deprecated("Use id instead") this.androidId, + @Deprecated("Use id instead") this.iosId, + required this.title, + this.action}) { + if (Util.isAndroid) { + // ignore: deprecated_member_use_from_same_package + this.id = this.id ?? this.androidId; + assert(this.id is int); + } else if (Util.isIOS) { + // ignore: deprecated_member_use_from_same_package + this.id = this.id ?? this.iosId; + } + assert(this.id != null && (this.id is int || this.id is String)); + } + + @ExchangeableObjectMethod(toMapMergeWith: true) + // ignore: unused_element + Map _toMapMergeWith() { + return {"androidId": androidId, "iosId": iosId}; + } +} diff --git a/lib/src/context_menu/context_menu_item.g.dart b/lib/src/context_menu/context_menu_item.g.dart new file mode 100644 index 00000000..242c1f2b --- /dev/null +++ b/lib/src/context_menu/context_menu_item.g.dart @@ -0,0 +1,81 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'context_menu_item.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///Class that represent an item of the [ContextMenu]. +class ContextMenuItem { + ///Menu item action that will be called when an user clicks on it. + dynamic Function()? action; + + ///Use [id] instead. + @Deprecated('Use id instead') + int? androidId; + + ///Menu item ID. It cannot be `null` and it can be a [String] or an [int]. + /// + ///**NOTE for Android**: it must be an [int] value. + dynamic id; + + ///Use [id] instead. + @Deprecated('Use id instead') + String? iosId; + + ///Menu item title. + String title; + ContextMenuItem( + {this.id, + @Deprecated("Use id instead") this.androidId, + @Deprecated("Use id instead") this.iosId, + required this.title, + this.action}) { + if (Util.isAndroid) { + this.id = this.id ?? this.androidId; + assert(this.id is int); + } else if (Util.isIOS) { + this.id = this.id ?? this.iosId; + } + assert(this.id != null && (this.id is int || this.id is String)); + } + + ///Gets a possible [ContextMenuItem] instance from a [Map] value. + static ContextMenuItem? fromMap(Map? map) { + if (map == null) { + return null; + } + final instance = ContextMenuItem( + androidId: map['id'], + id: map['id'], + iosId: map['id'], + title: map['title'], + ); + return instance; + } + + @ExchangeableObjectMethod(toMapMergeWith: true) + Map _toMapMergeWith() { + return {"androidId": androidId, "iosId": iosId}; + } + + ///Converts instance to a map. + Map toMap() { + return { + "id": id, + "title": title, + ..._toMapMergeWith(), + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'ContextMenuItem{id: $id, title: $title}'; + } +} diff --git a/lib/src/context_menu/context_menu_settings.dart b/lib/src/context_menu/context_menu_settings.dart new file mode 100644 index 00000000..dd6c001a --- /dev/null +++ b/lib/src/context_menu/context_menu_settings.dart @@ -0,0 +1,38 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +import 'context_menu.dart'; + +part 'context_menu_settings.g.dart'; + +///Class that represents available settings used by [ContextMenu]. +@ExchangeableObject(copyMethod: true) +class ContextMenuSettings_ { + ///Whether all the default system context menu items should be hidden or not. The default value is `false`. + bool hideDefaultSystemContextMenuItems; + + ContextMenuSettings_({this.hideDefaultSystemContextMenuItems = false}); +} + +///Use [ContextMenuSettings] instead. +@Deprecated("Use ContextMenuSettings instead") +class ContextMenuOptions { + ///Whether all the default system context menu items should be hidden or not. The default value is `false`. + bool hideDefaultSystemContextMenuItems; + + ContextMenuOptions({this.hideDefaultSystemContextMenuItems = false}); + + Map toMap() { + return { + "hideDefaultSystemContextMenuItems": hideDefaultSystemContextMenuItems + }; + } + + Map toJson() { + return this.toMap(); + } + + @override + String toString() { + return toMap().toString(); + } +} diff --git a/lib/src/context_menu/context_menu_settings.g.dart b/lib/src/context_menu/context_menu_settings.g.dart new file mode 100644 index 00000000..04646072 --- /dev/null +++ b/lib/src/context_menu/context_menu_settings.g.dart @@ -0,0 +1,47 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'context_menu_settings.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///Class that represents available settings used by [ContextMenu]. +class ContextMenuSettings { + ///Whether all the default system context menu items should be hidden or not. The default value is `false`. + bool hideDefaultSystemContextMenuItems; + ContextMenuSettings({this.hideDefaultSystemContextMenuItems = false}); + + ///Gets a possible [ContextMenuSettings] instance from a [Map] value. + static ContextMenuSettings? fromMap(Map? map) { + if (map == null) { + return null; + } + final instance = ContextMenuSettings(); + instance.hideDefaultSystemContextMenuItems = + map['hideDefaultSystemContextMenuItems']; + return instance; + } + + ///Converts instance to a map. + Map toMap() { + return { + "hideDefaultSystemContextMenuItems": hideDefaultSystemContextMenuItems, + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + ///Returns a copy of ContextMenuSettings. + ContextMenuSettings copy() { + return ContextMenuSettings.fromMap(toMap()) ?? ContextMenuSettings(); + } + + @override + String toString() { + return 'ContextMenuSettings{hideDefaultSystemContextMenuItems: $hideDefaultSystemContextMenuItems}'; + } +} diff --git a/lib/src/context_menu/main.dart b/lib/src/context_menu/main.dart new file mode 100644 index 00000000..5ff9f3f2 --- /dev/null +++ b/lib/src/context_menu/main.dart @@ -0,0 +1,4 @@ +export 'context_menu.dart' show ContextMenu; +export 'context_menu_item.dart' show ContextMenuItem; +export 'context_menu_settings.dart' + show ContextMenuSettings, ContextMenuOptions; diff --git a/lib/src/cookie_manager.dart b/lib/src/cookie_manager.dart index fb89e734..546c236a 100755 --- a/lib/src/cookie_manager.dart +++ b/lib/src/cookie_manager.dart @@ -274,8 +274,8 @@ class CookieManager { await headlessWebView.run(); await pageLoaded.future; - List documentCookies = (await headlessWebView.webViewController - !.evaluateJavascript(source: 'document.cookie') as String) + List documentCookies = (await headlessWebView.webViewController! + .evaluateJavascript(source: 'document.cookie') as String) .split(';') .map((documentCookie) => documentCookie.trim()) .toList(); diff --git a/lib/src/find_interaction/find_interaction_controller.dart b/lib/src/find_interaction/find_interaction_controller.dart index 1c8bcd42..d67e59b1 100644 --- a/lib/src/find_interaction/find_interaction_controller.dart +++ b/lib/src/find_interaction/find_interaction_controller.dart @@ -228,4 +228,4 @@ extension InternalFindInteractionController on FindInteractionController { } }); } -} \ No newline at end of file +} diff --git a/lib/src/in_app_browser/in_app_browser.dart b/lib/src/in_app_browser/in_app_browser.dart index a0d6b6f4..66653eb1 100755 --- a/lib/src/in_app_browser/in_app_browser.dart +++ b/lib/src/in_app_browser/in_app_browser.dart @@ -5,7 +5,7 @@ import 'dart:ui'; import 'package:flutter/services.dart'; -import '../context_menu.dart'; +import '../context_menu/context_menu.dart'; import '../find_interaction/find_interaction_controller.dart'; import '../pull_to_refresh/main.dart'; import '../types/main.dart'; @@ -16,6 +16,7 @@ import '../in_app_webview/in_app_webview_settings.dart'; import '../util.dart'; import '../print_job/main.dart'; import '../web_uri.dart'; +import 'in_app_browser_menu_item.dart'; import 'in_app_browser_settings.dart'; import '../debug_logging_settings.dart'; import '../pull_to_refresh/pull_to_refresh_controller.dart'; @@ -53,6 +54,8 @@ class InAppBrowser { InAppWebViewController? _webViewController; + Map _menuItems = new HashMap(); + ///WebView Controller that can be used to access the [InAppWebViewController] API. ///When [onExit] is fired, this will be `null` and cannot be used anymore. InAppWebViewController? get webViewController { @@ -62,9 +65,7 @@ class InAppBrowser { ///The window id of a [CreateWindowAction.windowId]. final int? windowId; - InAppBrowser( - {this.windowId, - this.initialUserScripts}) { + InAppBrowser({this.windowId, this.initialUserScripts}) { id = IdGenerator.generate(); } @@ -100,6 +101,15 @@ class InAppBrowser { _debugLog(call.method, call.arguments); onBrowserCreated(); break; + case "onMenuItemClicked": + _debugLog(call.method, call.arguments); + int id = call.arguments["id"].toInt(); + if (this._menuItems[id] != null) { + if (this._menuItems[id]?.onClick != null) { + this._menuItems[id]?.onClick!(); + } + } + break; case "onExit": _debugLog(call.method, call.arguments); _isOpened = false; @@ -111,6 +121,41 @@ class InAppBrowser { } } + Map _prepareOpenRequest( + { // ignore: deprecated_member_use_from_same_package + @Deprecated('Use settings instead') InAppBrowserClassOptions? options, + InAppBrowserClassSettings? settings}) { + assert(!_isOpened, 'The browser is already opened.'); + _isOpened = true; + _init(); + + var initialSettings = settings?.toMap() ?? + options?.toMap() ?? + InAppBrowserClassSettings().toMap(); + + Map pullToRefreshSettings = + pullToRefreshController?.settings.toMap() ?? + // ignore: deprecated_member_use_from_same_package + pullToRefreshController?.options.toMap() ?? + PullToRefreshSettings(enabled: false).toMap(); + + List> menuItemList = []; + _menuItems.forEach((key, value) { + menuItemList.add(value.toMap()); + }); + + Map args = {}; + args.putIfAbsent('id', () => id); + args.putIfAbsent('settings', () => initialSettings); + args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {}); + args.putIfAbsent('windowId', () => windowId); + args.putIfAbsent('initialUserScripts', + () => initialUserScripts?.map((e) => e.toMap()).toList() ?? []); + args.putIfAbsent('pullToRefreshSettings', () => pullToRefreshSettings); + args.putIfAbsent('menuItems', () => menuItemList); + return args; + } + ///Opens the [InAppBrowser] instance with an [urlRequest]. /// ///[urlRequest]: The [urlRequest] to load. @@ -128,30 +173,11 @@ class InAppBrowser { // ignore: deprecated_member_use_from_same_package @Deprecated('Use settings instead') InAppBrowserClassOptions? options, InAppBrowserClassSettings? settings}) async { - assert(!_isOpened, 'The browser is already opened.'); - _isOpened = true; assert(urlRequest.url != null && urlRequest.url.toString().isNotEmpty); - _init(); - var initialSettings = settings?.toMap() ?? - options?.toMap() ?? - InAppBrowserClassSettings().toMap(); - - Map pullToRefreshSettings = - pullToRefreshController?.settings.toMap() ?? - // ignore: deprecated_member_use_from_same_package - pullToRefreshController?.options.toMap() ?? - PullToRefreshSettings(enabled: false).toMap(); - - Map args = {}; - args.putIfAbsent('id', () => id); + Map args = + _prepareOpenRequest(options: options, settings: settings); args.putIfAbsent('urlRequest', () => urlRequest.toMap()); - args.putIfAbsent('settings', () => initialSettings); - args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {}); - args.putIfAbsent('windowId', () => windowId); - args.putIfAbsent('initialUserScripts', - () => initialUserScripts?.map((e) => e.toMap()).toList() ?? []); - args.putIfAbsent('pullToRefreshSettings', () => pullToRefreshSettings); await _sharedChannel.invokeMethod('open', args); } @@ -202,30 +228,11 @@ class InAppBrowser { // ignore: deprecated_member_use_from_same_package @Deprecated('Use settings instead') InAppBrowserClassOptions? options, InAppBrowserClassSettings? settings}) async { - assert(!_isOpened, 'The browser is already opened.'); - _isOpened = true; assert(assetFilePath.isNotEmpty); - _init(); - var initialSettings = settings?.toMap() ?? - options?.toMap() ?? - InAppBrowserClassSettings().toMap(); - - Map pullToRefreshSettings = - pullToRefreshController?.settings.toMap() ?? - // ignore: deprecated_member_use_from_same_package - pullToRefreshController?.options.toMap() ?? - PullToRefreshSettings(enabled: false).toMap(); - - Map args = {}; - args.putIfAbsent('id', () => id); + Map args = + _prepareOpenRequest(options: options, settings: settings); args.putIfAbsent('assetFilePath', () => assetFilePath); - args.putIfAbsent('settings', () => initialSettings); - args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {}); - args.putIfAbsent('windowId', () => windowId); - args.putIfAbsent('initialUserScripts', - () => initialUserScripts?.map((e) => e.toMap()).toList() ?? []); - args.putIfAbsent('pullToRefreshSettings', () => pullToRefreshSettings); await _sharedChannel.invokeMethod('open', args); } @@ -255,34 +262,14 @@ class InAppBrowser { // ignore: deprecated_member_use_from_same_package @Deprecated('Use settings instead') InAppBrowserClassOptions? options, InAppBrowserClassSettings? settings}) async { - assert(!_isOpened, 'The browser is already opened.'); - _isOpened = true; - _init(); - - var initialSettings = settings?.toMap() ?? - options?.toMap() ?? - InAppBrowserClassSettings().toMap(); - - Map pullToRefreshSettings = - pullToRefreshController?.settings.toMap() ?? - // ignore: deprecated_member_use_from_same_package - pullToRefreshController?.options.toMap() ?? - PullToRefreshSettings(enabled: false).toMap(); - - Map args = {}; - args.putIfAbsent('id', () => id); - args.putIfAbsent('settings', () => initialSettings); + Map args = + _prepareOpenRequest(options: options, settings: settings); args.putIfAbsent('data', () => data); args.putIfAbsent('mimeType', () => mimeType); args.putIfAbsent('encoding', () => encoding); args.putIfAbsent('baseUrl', () => baseUrl?.toString() ?? "about:blank"); args.putIfAbsent('historyUrl', () => (historyUrl ?? androidHistoryUrl)?.toString() ?? "about:blank"); - args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {}); - args.putIfAbsent('windowId', () => windowId); - args.putIfAbsent('initialUserScripts', - () => initialUserScripts?.map((e) => e.toMap()).toList() ?? []); - args.putIfAbsent('pullToRefreshSettings', () => pullToRefreshSettings); await _sharedChannel.invokeMethod('open', args); } @@ -300,6 +287,75 @@ class InAppBrowser { return await _sharedChannel.invokeMethod('openWithSystemBrowser', args); } + ///Adds a [InAppBrowserMenuItem] to the menu. + ///If the browser is already open, + ///it will take effect the next time it is opened. + /// + ///**Supported Platforms/Implementations**: + ///- Android + ///- iOS 14.0+ + void addMenuItem(InAppBrowserMenuItem menuItem) { + _menuItems[menuItem.id] = menuItem; + } + + ///Adds a list of [InAppBrowserMenuItem] to the menu. + ///If the browser is already open, + ///it will take effect the next time it is opened. + /// + ///**Supported Platforms/Implementations**: + ///- Android + ///- iOS 14.0+ + void addMenuItems(List menuItems) { + menuItems.forEach((menuItem) { + _menuItems[menuItem.id] = menuItem; + }); + } + + ///Removes the [menuItem] from the list. + ///Returns `true` if it was in the list, `false` otherwise. + ///If the browser is already open, + ///it will take effect the next time it is opened. + /// + ///**Supported Platforms/Implementations**: + ///- Android + ///- iOS 14.0+ + bool removeMenuItem(InAppBrowserMenuItem menuItem) { + return _menuItems.remove(menuItem.id) != null; + } + + ///Removes a list of [menuItems] from the list. + ///If the browser is already open, + ///it will take effect the next time it is opened. + /// + ///**Supported Platforms/Implementations**: + ///- Android + ///- iOS 14.0+ + void removeMenuItems(List menuItems) { + for (final menuItem in menuItems) { + removeMenuItem(menuItem); + } + } + + ///Removes all the menu items from the list. + ///If the browser is already open, + ///it will take effect the next time it is opened. + /// + ///**Supported Platforms/Implementations**: + ///- Android + ///- iOS 14.0+ + void removeAllMenuItem() { + _menuItems.clear(); + } + + ///Returns `true` if the [menuItem] has been already added, otherwise `false`. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS 14.0+ + bool hasMenuItem(InAppBrowserMenuItem menuItem) { + return _menuItems.containsKey(menuItem.id); + } + ///Displays an [InAppBrowser] window that was opened hidden. Calling this has no effect if the [InAppBrowser] was already visible. /// ///**Supported Platforms/Implementations**: diff --git a/lib/src/in_app_browser/in_app_browser_menu_item.dart b/lib/src/in_app_browser/in_app_browser_menu_item.dart new file mode 100644 index 00000000..a9e7d239 --- /dev/null +++ b/lib/src/in_app_browser/in_app_browser_menu_item.dart @@ -0,0 +1,82 @@ +import 'dart:typed_data'; +import 'dart:ui'; + +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +import '../util.dart'; + +import 'in_app_browser.dart'; +import '../types/main.dart'; + +part 'in_app_browser_menu_item.g.dart'; + +dynamic _serializeIcon(dynamic icon) { + return icon is Uint8List ? icon : icon?.toMap(); +} + +dynamic _deserializeIcon(dynamic icon) { + if (icon is Uint8List) { + return icon; + } + if (icon is Map) { + final iconMap = icon as Map; + if (iconMap.containsKey('defType')) { + return AndroidResource.fromMap(iconMap); + } + if (iconMap.containsKey('systemName')) { + return UIImage.fromMap(iconMap); + } + } + return null; +} + +///Class that represents a custom menu item for a [InAppBrowser] instance. +@SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(), + MacOSPlatform(), +]) +@ExchangeableObject() +class InAppBrowserMenuItem_ { + ///The menu item id. + int id; + + ///The title of the menu item. + String title; + + ///Item icon. + @ExchangeableObjectProperty( + serializer: _serializeIcon, deserializer: _deserializeIcon) + dynamic icon; + + ///Icon color. + @SupportedPlatforms(platforms: [ + AndroidPlatform(), + IOSPlatform(available: "13.0"), + MacOSPlatform(), + ]) + Color_? iconColor; + + ///Item order. + int? order; + + ///Show this item as a button in the Action Bar. + bool showAsAction; + + ///Callback function to be invoked when the menu item is clicked + void Function()? onClick; + + InAppBrowserMenuItem_( + {required this.id, + required this.title, + this.icon, + this.iconColor, + this.onClick, + this.order, + this.showAsAction = false}) { + assert(this.icon == null || + this.icon is Uint8List || + this.icon is UIImage || + this.icon is AndroidResource); + } +} diff --git a/lib/src/in_app_browser/in_app_browser_menu_item.g.dart b/lib/src/in_app_browser/in_app_browser_menu_item.g.dart new file mode 100644 index 00000000..e7382b27 --- /dev/null +++ b/lib/src/in_app_browser/in_app_browser_menu_item.g.dart @@ -0,0 +1,95 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'in_app_browser_menu_item.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///Class that represents a custom menu item for a [InAppBrowser] instance. +/// +///**Supported Platforms/Implementations**: +///- Android native WebView +///- iOS +///- MacOS +class InAppBrowserMenuItem { + ///Item icon. + dynamic icon; + + ///Icon color. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS 13.0+ + ///- MacOS + Color? iconColor; + + ///The menu item id. + int id; + + ///Callback function to be invoked when the menu item is clicked + void Function()? onClick; + + ///Item order. + int? order; + + ///Show this item as a button in the Action Bar. + bool showAsAction; + + ///The title of the menu item. + String title; + + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS + ///- MacOS + InAppBrowserMenuItem( + {this.icon, + this.iconColor, + required this.id, + this.onClick, + this.order, + this.showAsAction = false, + required this.title}); + + ///Gets a possible [InAppBrowserMenuItem] instance from a [Map] value. + static InAppBrowserMenuItem? fromMap(Map? map) { + if (map == null) { + return null; + } + final instance = InAppBrowserMenuItem( + icon: _deserializeIcon(map['icon']), + iconColor: map['iconColor'] != null + ? UtilColor.fromStringRepresentation(map['iconColor']) + : null, + id: map['id'], + order: map['order'], + title: map['title'], + ); + instance.showAsAction = map['showAsAction']; + return instance; + } + + ///Converts instance to a map. + Map toMap() { + return { + "icon": _serializeIcon(icon), + "iconColor": iconColor?.toHex(), + "id": id, + "order": order, + "showAsAction": showAsAction, + "title": title, + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'InAppBrowserMenuItem{icon: $icon, iconColor: $iconColor, id: $id, order: $order, showAsAction: $showAsAction, title: $title}'; + } +} diff --git a/lib/src/in_app_browser/in_app_browser_settings.dart b/lib/src/in_app_browser/in_app_browser_settings.dart index b04624f0..d8d61dff 100755 --- a/lib/src/in_app_browser/in_app_browser_settings.dart +++ b/lib/src/in_app_browser/in_app_browser_settings.dart @@ -139,6 +139,13 @@ class InAppBrowserSettings_ ///- MacOS bool? hideProgressBar; + ///Set to `true` to hide the default menu items. The default value is `false`. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS + bool? hideDefaultMenuItems; + ///Set to `true` if you want the title should be displayed. The default value is `false`. /// ///**Supported Platforms/Implementations**: @@ -224,6 +231,18 @@ class InAppBrowserSettings_ ///- iOS Color_? closeButtonColor; + ///Set to `true` to hide the close button. The default value is `false`. + /// + ///**Supported Platforms/Implementations**: + ///- iOS + bool? hideCloseButton; + + ///Set the custom color for the menu button. + /// + ///**Supported Platforms/Implementations**: + ///- iOS + Color_? menuButtonColor; + ///Set the custom modal presentation style when presenting the WebView. The default value is [ModalPresentationStyle.FULL_SCREEN]. /// ///**Supported Platforms/Implementations**: @@ -277,6 +296,7 @@ class InAppBrowserSettings_ this.toolbarTopBackgroundColor, this.hideUrlBar = false, this.hideProgressBar = false, + this.hideDefaultMenuItems = false, this.toolbarTopTranslucent = true, this.toolbarTopTintColor, this.hideToolbarBottom = false, @@ -285,6 +305,7 @@ class InAppBrowserSettings_ this.toolbarBottomTranslucent = true, this.closeButtonCaption, this.closeButtonColor, + this.hideCloseButton = false, this.presentationStyle = ModalPresentationStyle_.FULL_SCREEN, this.transitionStyle = ModalTransitionStyle_.COVER_VERTICAL, this.hideTitleBar = false, diff --git a/lib/src/in_app_browser/in_app_browser_settings.g.dart b/lib/src/in_app_browser/in_app_browser_settings.g.dart index 511f7d11..9d18bc54 100644 --- a/lib/src/in_app_browser/in_app_browser_settings.g.dart +++ b/lib/src/in_app_browser/in_app_browser_settings.g.dart @@ -42,6 +42,19 @@ class InAppBrowserSettings ///- MacOS bool? hidden; + ///Set to `true` to hide the close button. The default value is `false`. + /// + ///**Supported Platforms/Implementations**: + ///- iOS + bool? hideCloseButton; + + ///Set to `true` to hide the default menu items. The default value is `false`. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS + bool? hideDefaultMenuItems; + ///Set to `true` to hide the progress bar when the WebView is loading a page. The default value is `false`. /// ///**Supported Platforms/Implementations**: @@ -78,6 +91,12 @@ class InAppBrowserSettings ///- MacOS bool? hideUrlBar; + ///Set the custom color for the menu button. + /// + ///**Supported Platforms/Implementations**: + ///- iOS + Color? menuButtonColor; + ///Set the custom modal presentation style when presenting the WebView. The default value is [ModalPresentationStyle.FULL_SCREEN]. /// ///**Supported Platforms/Implementations**: @@ -187,6 +206,8 @@ class InAppBrowserSettings this.closeButtonColor, this.closeOnCannotGoBack = true, this.hidden = false, + this.hideCloseButton = false, + this.hideDefaultMenuItems = false, this.hideProgressBar = false, this.hideTitleBar = false, this.hideToolbarBottom = false, @@ -243,11 +264,16 @@ class InAppBrowserSettings instance.allowGoBackWithBackButton = map['allowGoBackWithBackButton']; instance.closeOnCannotGoBack = map['closeOnCannotGoBack']; instance.hidden = map['hidden']; + instance.hideCloseButton = map['hideCloseButton']; + instance.hideDefaultMenuItems = map['hideDefaultMenuItems']; instance.hideProgressBar = map['hideProgressBar']; instance.hideTitleBar = map['hideTitleBar']; instance.hideToolbarBottom = map['hideToolbarBottom']; instance.hideToolbarTop = map['hideToolbarTop']; instance.hideUrlBar = map['hideUrlBar']; + instance.menuButtonColor = map['menuButtonColor'] != null + ? UtilColor.fromStringRepresentation(map['menuButtonColor']) + : null; instance.presentationStyle = ModalPresentationStyle.fromNativeValue(map['presentationStyle']); instance.shouldCloseOnBackButtonPressed = @@ -271,11 +297,14 @@ class InAppBrowserSettings "closeButtonColor": closeButtonColor?.toHex(), "closeOnCannotGoBack": closeOnCannotGoBack, "hidden": hidden, + "hideCloseButton": hideCloseButton, + "hideDefaultMenuItems": hideDefaultMenuItems, "hideProgressBar": hideProgressBar, "hideTitleBar": hideTitleBar, "hideToolbarBottom": hideToolbarBottom, "hideToolbarTop": hideToolbarTop, "hideUrlBar": hideUrlBar, + "menuButtonColor": menuButtonColor?.toHex(), "presentationStyle": presentationStyle?.toNativeValue(), "shouldCloseOnBackButtonPressed": shouldCloseOnBackButtonPressed, "toolbarBottomBackgroundColor": toolbarBottomBackgroundColor?.toHex(), @@ -308,6 +337,6 @@ class InAppBrowserSettings @override String toString() { - return 'InAppBrowserSettings{allowGoBackWithBackButton: $allowGoBackWithBackButton, closeButtonCaption: $closeButtonCaption, closeButtonColor: $closeButtonColor, closeOnCannotGoBack: $closeOnCannotGoBack, hidden: $hidden, hideProgressBar: $hideProgressBar, hideTitleBar: $hideTitleBar, hideToolbarBottom: $hideToolbarBottom, hideToolbarTop: $hideToolbarTop, hideUrlBar: $hideUrlBar, presentationStyle: $presentationStyle, shouldCloseOnBackButtonPressed: $shouldCloseOnBackButtonPressed, toolbarBottomBackgroundColor: $toolbarBottomBackgroundColor, toolbarBottomTintColor: $toolbarBottomTintColor, toolbarBottomTranslucent: $toolbarBottomTranslucent, toolbarTopBackgroundColor: $toolbarTopBackgroundColor, toolbarTopBarTintColor: $toolbarTopBarTintColor, toolbarTopFixedTitle: $toolbarTopFixedTitle, toolbarTopTintColor: $toolbarTopTintColor, toolbarTopTranslucent: $toolbarTopTranslucent, transitionStyle: $transitionStyle, windowAlphaValue: $windowAlphaValue, windowFrame: $windowFrame, windowStyleMask: $windowStyleMask, windowTitlebarSeparatorStyle: $windowTitlebarSeparatorStyle, windowType: $windowType}'; + return 'InAppBrowserSettings{allowGoBackWithBackButton: $allowGoBackWithBackButton, closeButtonCaption: $closeButtonCaption, closeButtonColor: $closeButtonColor, closeOnCannotGoBack: $closeOnCannotGoBack, hidden: $hidden, hideCloseButton: $hideCloseButton, hideDefaultMenuItems: $hideDefaultMenuItems, hideProgressBar: $hideProgressBar, hideTitleBar: $hideTitleBar, hideToolbarBottom: $hideToolbarBottom, hideToolbarTop: $hideToolbarTop, hideUrlBar: $hideUrlBar, menuButtonColor: $menuButtonColor, presentationStyle: $presentationStyle, shouldCloseOnBackButtonPressed: $shouldCloseOnBackButtonPressed, toolbarBottomBackgroundColor: $toolbarBottomBackgroundColor, toolbarBottomTintColor: $toolbarBottomTintColor, toolbarBottomTranslucent: $toolbarBottomTranslucent, toolbarTopBackgroundColor: $toolbarTopBackgroundColor, toolbarTopBarTintColor: $toolbarTopBarTintColor, toolbarTopFixedTitle: $toolbarTopFixedTitle, toolbarTopTintColor: $toolbarTopTintColor, toolbarTopTranslucent: $toolbarTopTranslucent, transitionStyle: $transitionStyle, windowAlphaValue: $windowAlphaValue, windowFrame: $windowFrame, windowStyleMask: $windowStyleMask, windowTitlebarSeparatorStyle: $windowTitlebarSeparatorStyle, windowType: $windowType}'; } } diff --git a/lib/src/in_app_browser/main.dart b/lib/src/in_app_browser/main.dart index 0c541535..df709ca5 100644 --- a/lib/src/in_app_browser/main.dart +++ b/lib/src/in_app_browser/main.dart @@ -8,3 +8,4 @@ export 'in_app_browser_settings.dart' InAppBrowserOptions; export 'android/main.dart'; export 'apple/main.dart'; +export 'in_app_browser_menu_item.dart' show InAppBrowserMenuItem; diff --git a/lib/src/in_app_webview/headless_in_app_webview.dart b/lib/src/in_app_webview/headless_in_app_webview.dart index f7c53199..37eee388 100644 --- a/lib/src/in_app_webview/headless_in_app_webview.dart +++ b/lib/src/in_app_webview/headless_in_app_webview.dart @@ -5,7 +5,7 @@ import 'dart:ui'; import 'package:flutter/services.dart'; import '../util.dart'; -import '../context_menu.dart'; +import '../context_menu/context_menu.dart'; import '../find_interaction/find_interaction_controller.dart'; import '../types/main.dart'; import '../print_job/main.dart'; @@ -372,7 +372,8 @@ class HeadlessInAppWebView implements WebView, Disposable { Map args = {}; Map sizeMap = - (await _channel?.invokeMethod('getSize', args))?.cast(); + (await _channel?.invokeMethod('getSize', args)) + ?.cast(); return MapSize.fromMap(sizeMap); } diff --git a/lib/src/in_app_webview/in_app_webview.dart b/lib/src/in_app_webview/in_app_webview.dart index e7b2ae90..64a22036 100755 --- a/lib/src/in_app_webview/in_app_webview.dart +++ b/lib/src/in_app_webview/in_app_webview.dart @@ -14,7 +14,7 @@ import '../util.dart'; import '../find_interaction/find_interaction_controller.dart'; import '../web/web_platform_manager.dart'; -import '../context_menu.dart'; +import '../context_menu/context_menu.dart'; import '../types/main.dart'; import '../print_job/main.dart'; @@ -73,8 +73,7 @@ class InAppWebView extends StatefulWidget implements WebView { this.initialUrlRequest, this.initialFile, this.initialData, - @Deprecated('Use initialSettings instead') - this.initialOptions, + @Deprecated('Use initialSettings instead') this.initialOptions, this.initialSettings, this.initialUserScripts, this.pullToRefreshController, @@ -83,19 +82,16 @@ class InAppWebView extends StatefulWidget implements WebView { this.onWebViewCreated, this.onLoadStart, this.onLoadStop, - @Deprecated("Use onReceivedError instead") - this.onLoadError, + @Deprecated("Use onReceivedError instead") this.onLoadError, this.onReceivedError, - @Deprecated("Use onReceivedHttpError instead") - this.onLoadHttpError, + @Deprecated("Use onReceivedHttpError instead") this.onLoadHttpError, this.onReceivedHttpError, this.onConsoleMessage, this.onProgressChanged, this.shouldOverrideUrlLoading, this.onLoadResource, this.onScrollChanged, - @Deprecated('Use onDownloadStartRequest instead') - this.onDownloadStart, + @Deprecated('Use onDownloadStartRequest instead') this.onDownloadStart, this.onDownloadStartRequest, @Deprecated('Use onLoadResourceWithCustomScheme instead') this.onLoadResourceCustomScheme, @@ -115,8 +111,7 @@ class InAppWebView extends StatefulWidget implements WebView { this.onAjaxProgress, this.shouldInterceptFetchRequest, this.onUpdateVisitedHistory, - @Deprecated("Use onPrintRequest instead") - this.onPrint, + @Deprecated("Use onPrintRequest instead") this.onPrint, this.onPrintRequest, this.onLongPressHitTestResult, this.onEnterFullscreen, @@ -127,8 +122,7 @@ class InAppWebView extends StatefulWidget implements WebView { this.onWindowBlur, this.onOverScrolled, this.onZoomScaleChanged, - @Deprecated('Use onSafeBrowsingHit instead') - this.androidOnSafeBrowsingHit, + @Deprecated('Use onSafeBrowsingHit instead') this.androidOnSafeBrowsingHit, this.onSafeBrowsingHit, @Deprecated('Use onPermissionRequest instead') this.androidOnPermissionRequest, @@ -154,16 +148,13 @@ class InAppWebView extends StatefulWidget implements WebView { @Deprecated('Use onFormResubmission instead') this.androidOnFormResubmission, this.onFormResubmission, - @Deprecated('Use onZoomScaleChanged instead') - this.androidOnScaleChanged, - @Deprecated('Use onReceivedIcon instead') - this.androidOnReceivedIcon, + @Deprecated('Use onZoomScaleChanged instead') this.androidOnScaleChanged, + @Deprecated('Use onReceivedIcon instead') this.androidOnReceivedIcon, this.onReceivedIcon, @Deprecated('Use onReceivedTouchIconUrl instead') this.androidOnReceivedTouchIconUrl, this.onReceivedTouchIconUrl, - @Deprecated('Use onJsBeforeUnload instead') - this.androidOnJsBeforeUnload, + @Deprecated('Use onJsBeforeUnload instead') this.androidOnJsBeforeUnload, this.onJsBeforeUnload, @Deprecated('Use onReceivedLoginRequest instead') this.androidOnReceivedLoginRequest, diff --git a/lib/src/in_app_webview/in_app_webview_controller.dart b/lib/src/in_app_webview/in_app_webview_controller.dart index 95396694..ce252146 100644 --- a/lib/src/in_app_webview/in_app_webview_controller.dart +++ b/lib/src/in_app_webview/in_app_webview_controller.dart @@ -9,17 +9,16 @@ import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; +import '../context_menu/main.dart'; +import '../web_message/main.dart'; import '../web_uri.dart'; import 'android/in_app_webview_controller.dart'; import 'apple/in_app_webview_controller.dart'; -import '../context_menu.dart'; import '../types/main.dart'; import '../in_app_browser/in_app_browser.dart'; import '../web_storage/web_storage.dart'; import '../util.dart'; -import '../web_message/web_message_channel.dart'; -import '../web_message/web_message_listener.dart'; import '../android/webview_feature.dart'; import 'headless_in_app_webview.dart'; diff --git a/lib/src/in_app_webview/in_app_webview_keep_alive.dart b/lib/src/in_app_webview/in_app_webview_keep_alive.dart index b5405c84..1e30ba7c 100644 --- a/lib/src/in_app_webview/in_app_webview_keep_alive.dart +++ b/lib/src/in_app_webview/in_app_webview_keep_alive.dart @@ -27,7 +27,7 @@ class InAppWebViewControllerKeepAliveProps { InAppWebViewControllerKeepAliveProps( {required this.javaScriptHandlersMap, - required this.userScripts, - required this.webMessageListenerObjNames, - required this.injectedScriptsFromURL}); -} \ No newline at end of file + required this.userScripts, + required this.webMessageListenerObjNames, + required this.injectedScriptsFromURL}); +} diff --git a/lib/src/in_app_webview/in_app_webview_settings.dart b/lib/src/in_app_webview/in_app_webview_settings.dart index 0e66139d..74be44c0 100755 --- a/lib/src/in_app_webview/in_app_webview_settings.dart +++ b/lib/src/in_app_webview/in_app_webview_settings.dart @@ -31,7 +31,7 @@ import '../in_app_browser/in_app_browser_settings.dart'; import 'webview.dart'; import '../android/webview_feature.dart'; import '../in_app_webview/in_app_webview_controller.dart'; -import '../context_menu.dart'; +import '../context_menu/context_menu.dart'; import '../in_app_browser/in_app_browser.dart'; part 'in_app_webview_settings.g.dart'; diff --git a/lib/src/in_app_webview/webview.dart b/lib/src/in_app_webview/webview.dart index 0fa1ca48..45df9407 100644 --- a/lib/src/in_app_webview/webview.dart +++ b/lib/src/in_app_webview/webview.dart @@ -5,7 +5,7 @@ import 'dart:ui'; import '../find_interaction/find_interaction_controller.dart'; import '../pull_to_refresh/pull_to_refresh_controller.dart'; -import '../context_menu.dart'; +import '../context_menu/context_menu.dart'; import '../types/main.dart'; import '../web_uri.dart'; diff --git a/lib/src/main.dart b/lib/src/main.dart index c1e05720..a42f0813 100644 --- a/lib/src/main.dart +++ b/lib/src/main.dart @@ -10,7 +10,7 @@ export 'cookie_manager.dart'; export 'in_app_localhost_server.dart'; export 'content_blocker.dart'; export 'http_auth_credentials_database.dart'; -export 'context_menu.dart'; +export 'context_menu/main.dart'; export 'pull_to_refresh/main.dart'; export 'web_message/main.dart'; export 'web_authentication_session/main.dart'; diff --git a/lib/src/print_job/print_job_controller.dart b/lib/src/print_job/print_job_controller.dart index 44ece029..4f8c7669 100644 --- a/lib/src/print_job/print_job_controller.dart +++ b/lib/src/print_job/print_job_controller.dart @@ -101,7 +101,8 @@ class PrintJobController implements Disposable { Future getInfo() async { Map args = {}; Map? infoMap = - (await _channel?.invokeMethod('getInfo', args))?.cast(); + (await _channel?.invokeMethod('getInfo', args)) + ?.cast(); return PrintJobInfo.fromMap(infoMap); } diff --git a/lib/src/pull_to_refresh/main.dart b/lib/src/pull_to_refresh/main.dart index ae4ef16a..1c68b91f 100644 --- a/lib/src/pull_to_refresh/main.dart +++ b/lib/src/pull_to_refresh/main.dart @@ -1,4 +1,3 @@ -export 'pull_to_refresh_controller.dart' - show PullToRefreshController; +export 'pull_to_refresh_controller.dart' show PullToRefreshController; export 'pull_to_refresh_settings.dart' show PullToRefreshSettings, PullToRefreshOptions; diff --git a/lib/src/pull_to_refresh/pull_to_refresh_controller.dart b/lib/src/pull_to_refresh/pull_to_refresh_controller.dart index a91cf575..f15d2ee1 100644 --- a/lib/src/pull_to_refresh/pull_to_refresh_controller.dart +++ b/lib/src/pull_to_refresh/pull_to_refresh_controller.dart @@ -239,4 +239,4 @@ extension InternalPullToRefreshController on PullToRefreshController { } }); } -} \ No newline at end of file +} diff --git a/lib/src/types/android_resource.dart b/lib/src/types/android_resource.dart index da46ccad..29d98eb1 100644 --- a/lib/src/types/android_resource.dart +++ b/lib/src/types/android_resource.dart @@ -7,6 +7,9 @@ part 'android_resource.g.dart'; class AndroidResource_ { ///Android resource name. /// + ///A list of available `android.R.drawable` can be found + ///[here](https://developer.android.com/reference/android/R.drawable). + /// ///A list of available `android.R.anim` can be found ///[here](https://developer.android.com/reference/android/R.anim). /// @@ -43,4 +46,9 @@ class AndroidResource_ { static AndroidResource_ id({required String name, String? defPackage}) { return AndroidResource_(name: name, defType: "id", defPackage: defPackage); } + + static AndroidResource_ drawable({required String name, String? defPackage}) { + return AndroidResource_( + name: name, defType: "drawable", defPackage: defPackage); + } } diff --git a/lib/src/types/android_resource.g.dart b/lib/src/types/android_resource.g.dart index bbe768c0..8d1880a3 100644 --- a/lib/src/types/android_resource.g.dart +++ b/lib/src/types/android_resource.g.dart @@ -22,6 +22,9 @@ class AndroidResource { ///Android resource name. /// + ///A list of available `android.R.drawable` can be found + ///[here](https://developer.android.com/reference/android/R.drawable). + /// ///A list of available `android.R.anim` can be found ///[here](https://developer.android.com/reference/android/R.anim). /// @@ -58,6 +61,11 @@ class AndroidResource { return AndroidResource(name: name, defType: "id", defPackage: defPackage); } + static AndroidResource drawable({required String name, String? defPackage}) { + return AndroidResource( + name: name, defType: "drawable", defPackage: defPackage); + } + ///Converts instance to a map. Map toMap() { return { diff --git a/lib/src/types/trusted_web_activity_immersive_display_mode.g.dart b/lib/src/types/trusted_web_activity_immersive_display_mode.g.dart index 82a15f42..a5370c9e 100644 --- a/lib/src/types/trusted_web_activity_immersive_display_mode.g.dart +++ b/lib/src/types/trusted_web_activity_immersive_display_mode.g.dart @@ -56,9 +56,9 @@ class TrustedWebActivityImmersiveDisplayMode ///Converts instance to a map. Map toMap() { return { - ..._toMapMergeWith(), "displayCutoutMode": displayCutoutMode.toNativeValue(), "isSticky": isSticky, + ..._toMapMergeWith(), }; } diff --git a/lib/src/types/ui_image.dart b/lib/src/types/ui_image.dart index 28f3aae1..e2ecda37 100644 --- a/lib/src/types/ui_image.dart +++ b/lib/src/types/ui_image.dart @@ -4,20 +4,24 @@ import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_i part 'ui_image.g.dart'; -///Class that represents an object that manages iOS image data in your app. +///Class that represents an object that manages iOS and MacOS image data in your app. /// -///Check [UIKit.UIImage](https://developer.apple.com/documentation/uikit/uiimage) for more details. +///Check iOS [UIKit.UIImage](https://developer.apple.com/documentation/uikit/uiimage) for more details. +///Check MacOS [AppKit.NSImage](https://developer.apple.com/documentation/appkit/nsimage) for more details. /// ///**Supported Platforms/Implementations**: ///- iOS +///- MacOS @ExchangeableObject() class UIImage_ { ///The name of the image asset or file. String? name; ///The name of the system symbol image. - /// - ///**NOTE**: available on iOS 13.0+. + @SupportedPlatforms(platforms: [ + IOSPlatform(available: "13.0"), + MacOSPlatform(available: "11.0"), + ]) String? systemName; ///The data object containing the image data. diff --git a/lib/src/types/ui_image.g.dart b/lib/src/types/ui_image.g.dart index 9ab59e75..0d40eb3f 100644 --- a/lib/src/types/ui_image.g.dart +++ b/lib/src/types/ui_image.g.dart @@ -6,12 +6,14 @@ part of 'ui_image.dart'; // ExchangeableObjectGenerator // ************************************************************************** -///Class that represents an object that manages iOS image data in your app. +///Class that represents an object that manages iOS and MacOS image data in your app. /// -///Check [UIKit.UIImage](https://developer.apple.com/documentation/uikit/uiimage) for more details. +///Check iOS [UIKit.UIImage](https://developer.apple.com/documentation/uikit/uiimage) for more details. +///Check MacOS [AppKit.NSImage](https://developer.apple.com/documentation/appkit/nsimage) for more details. /// ///**Supported Platforms/Implementations**: ///- iOS +///- MacOS class UIImage { ///The data object containing the image data. Uint8List? data; @@ -21,7 +23,9 @@ class UIImage { ///The name of the system symbol image. /// - ///**NOTE**: available on iOS 13.0+. + ///**Supported Platforms/Implementations**: + ///- iOS 13.0+ + ///- MacOS 11.0+ String? systemName; UIImage({this.name, this.systemName, this.data}) { assert(this.name != null || this.systemName != null || this.data != null); diff --git a/lib/src/web_message/main.dart b/lib/src/web_message/main.dart index 6173cba8..f8d6852a 100644 --- a/lib/src/web_message/main.dart +++ b/lib/src/web_message/main.dart @@ -1,2 +1,4 @@ -export 'web_message_channel.dart'; +export 'web_message.dart' show WebMessage; +export 'web_message_port.dart' show WebMessagePort; +export 'web_message_channel.dart' show WebMessageChannel; export 'web_message_listener.dart'; diff --git a/lib/src/web_message/web_message.dart b/lib/src/web_message/web_message.dart new file mode 100644 index 00000000..52fc4603 --- /dev/null +++ b/lib/src/web_message/web_message.dart @@ -0,0 +1,18 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +import 'web_message_port.dart'; + +part 'web_message.g.dart'; + +///The Dart representation of the HTML5 PostMessage event. +///See https://html.spec.whatwg.org/multipage/comms.html#the-messageevent-interfaces for definition of a MessageEvent in HTML5. +@ExchangeableObject() +class WebMessage_ { + ///The data of the message. + String? data; + + ///The ports that are sent with the message. + List? ports; + + WebMessage_({this.data, this.ports}); +} diff --git a/lib/src/web_message/web_message.g.dart b/lib/src/web_message/web_message.g.dart new file mode 100644 index 00000000..5e2c41b7 --- /dev/null +++ b/lib/src/web_message/web_message.g.dart @@ -0,0 +1,50 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'web_message.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///The Dart representation of the HTML5 PostMessage event. +///See https://html.spec.whatwg.org/multipage/comms.html#the-messageevent-interfaces for definition of a MessageEvent in HTML5. +class WebMessage { + ///The data of the message. + String? data; + + ///The ports that are sent with the message. + List? ports; + WebMessage({this.data, this.ports}); + + ///Gets a possible [WebMessage] instance from a [Map] value. + static WebMessage? fromMap(Map? map) { + if (map == null) { + return null; + } + final instance = WebMessage( + data: map['data'], + ports: map['ports'] != null + ? List.from(map['ports'].map((e) => e)) + : null, + ); + return instance; + } + + ///Converts instance to a map. + Map toMap() { + return { + "data": data, + "ports": ports?.map((e) => e.toMap()).toList(), + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'WebMessage{data: $data, ports: $ports}'; + } +} diff --git a/lib/src/web_message/web_message_channel.dart b/lib/src/web_message/web_message_channel.dart index 7ca3751f..0035b6c6 100644 --- a/lib/src/web_message/web_message_channel.dart +++ b/lib/src/web_message/web_message_channel.dart @@ -1,6 +1,5 @@ import 'package:flutter/services.dart'; -import '../types/main.dart'; -import '../in_app_webview/in_app_webview_controller.dart'; +import 'web_message_port.dart'; ///The representation of the [HTML5 message channels](https://html.spec.whatwg.org/multipage/web-messaging.html#message-channels). /// @@ -42,8 +41,8 @@ class WebMessageChannel { id: map["id"], port1: WebMessagePort(index: 0), port2: WebMessagePort(index: 1)); - webMessageChannel.port1._webMessageChannel = webMessageChannel; - webMessageChannel.port2._webMessageChannel = webMessageChannel; + webMessageChannel.port1.webMessageChannel = webMessageChannel; + webMessageChannel.port2.webMessageChannel = webMessageChannel; return webMessageChannel; } @@ -52,9 +51,9 @@ class WebMessageChannel { case "onMessage": int index = call.arguments["index"]; var port = index == 0 ? this.port1 : this.port2; - if (port._onMessage != null) { + if (port.onMessage != null) { String? message = call.arguments["message"]; - port._onMessage!(message); + port.onMessage!(message); } break; default: @@ -62,101 +61,13 @@ class WebMessageChannel { } return null; } -} - -///The representation of the [HTML5 message ports](https://html.spec.whatwg.org/multipage/comms.html#messageport). -/// -///A Message port represents one endpoint of a Message Channel. In Android webview, there is no separate Message Channel object. -///When a message channel is created, both ports are tangled to each other and started. -///See [InAppWebViewController.createWebMessageChannel] for creating a message channel. -/// -///When a message port is first created or received via transfer, it does not have a [WebMessageCallback] to receive web messages. -///On Android, the messages are queued until a [WebMessageCallback] is set. -/// -///A message port should be closed when it is not used by the embedder application anymore. -///A closed port cannot be transferred or cannot be reopened to send messages. -///Close can be called multiple times. -/// -///When a port is transferred to JavaScript, it cannot be used to send or receive messages at the Dart side anymore. -///Different from HTML5 Spec, a port cannot be transferred if one of these has ever happened: i. a message callback was set, ii. a message was posted on it. -///A transferred port cannot be closed by the application, since the ownership is also transferred. -/// -///It is possible to transfer both ports of a channel to JavaScript, for example for communication between subframes. -class WebMessagePort { - late final int _index; - - WebMessageCallback? _onMessage; - late WebMessageChannel _webMessageChannel; - - WebMessagePort({required int index}) { - this._index = index; - } - - ///Sets a callback to receive message events on the main thread. - Future setWebMessageCallback(WebMessageCallback? onMessage) async { - Map args = {}; - args.putIfAbsent('index', () => this._index); - await _webMessageChannel._channel - ?.invokeMethod('setWebMessageCallback', args); - this._onMessage = onMessage; - } - - ///Post a WebMessage to the entangled port. - Future postMessage(WebMessage message) async { - Map args = {}; - args.putIfAbsent('index', () => this._index); - args.putIfAbsent('message', () => message.toMap()); - await _webMessageChannel._channel?.invokeMethod('postMessage', args); - } - - ///Close the message port and free any resources associated with it. - Future close() async { - Map args = {}; - args.putIfAbsent('index', () => this._index); - await _webMessageChannel._channel?.invokeMethod('close', args); - } - - Map toMap() { - return { - "index": this._index, - "webMessageChannelId": this._webMessageChannel.id - }; - } - - Map toJson() { - return this.toMap(); - } @override String toString() { - return toMap().toString(); + return 'WebMessageChannel{id: $id, port1: $port1, port2: $port2}'; } } -///The Dart representation of the HTML5 PostMessage event. -///See https://html.spec.whatwg.org/multipage/comms.html#the-messageevent-interfaces for definition of a MessageEvent in HTML5. -class WebMessage { - ///The data of the message. - String? data; - - ///The ports that are sent with the message. - List? ports; - - WebMessage({this.data, this.ports}); - - Map toMap() { - return { - "data": this.data, - "ports": this.ports?.map((e) => e.toMap()).toList(), - }; - } - - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } +extension InternalWebMessageChannel on WebMessageChannel { + MethodChannel? get channel => _channel; } diff --git a/lib/src/web_message/web_message_listener.dart b/lib/src/web_message/web_message_listener.dart index 03c7ebfa..d2f80909 100644 --- a/lib/src/web_message/web_message_listener.dart +++ b/lib/src/web_message/web_message_listener.dart @@ -92,7 +92,7 @@ class WebMessageListener { @override String toString() { - return 'WebMessageListener{id: $id, jsObjectName: $jsObjectName, allowedOriginRules: $allowedOriginRules}'; + return 'WebMessageListener{id: $id, jsObjectName: $jsObjectName, allowedOriginRules: $allowedOriginRules, replyProxy: $_replyProxy}'; } } @@ -116,4 +116,9 @@ class JavaScriptReplyProxy { args.putIfAbsent('message', () => message); await _webMessageListener._channel?.invokeMethod('postMessage', args); } + + @override + String toString() { + return 'JavaScriptReplyProxy{}'; + } } diff --git a/lib/src/web_message/web_message_port.dart b/lib/src/web_message/web_message_port.dart new file mode 100644 index 00000000..57c42643 --- /dev/null +++ b/lib/src/web_message/web_message_port.dart @@ -0,0 +1,90 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +import '../types/web_message_callback.dart'; +import 'web_message.dart'; +import 'web_message_channel.dart'; + +///The representation of the [HTML5 message ports](https://html.spec.whatwg.org/multipage/comms.html#messageport). +/// +///A Message port represents one endpoint of a Message Channel. In Android webview, there is no separate Message Channel object. +///When a message channel is created, both ports are tangled to each other and started. +///See [InAppWebViewController.createWebMessageChannel] for creating a message channel. +/// +///When a message port is first created or received via transfer, it does not have a [WebMessageCallback] to receive web messages. +///On Android, the messages are queued until a [WebMessageCallback] is set. +/// +///A message port should be closed when it is not used by the embedder application anymore. +///A closed port cannot be transferred or cannot be reopened to send messages. +///Close can be called multiple times. +/// +///When a port is transferred to JavaScript, it cannot be used to send or receive messages at the Dart side anymore. +///Different from HTML5 Spec, a port cannot be transferred if one of these has ever happened: i. a message callback was set, ii. a message was posted on it. +///A transferred port cannot be closed by the application, since the ownership is also transferred. +/// +///It is possible to transfer both ports of a channel to JavaScript, for example for communication between subframes. +class WebMessagePort { + late final int _index; + + WebMessageCallback? _onMessage; + late WebMessageChannel _webMessageChannel; + + @ExchangeableObjectConstructor() + WebMessagePort({required int index}) { + this._index = index; + } + + ///Sets a callback to receive message events on the main thread. + Future setWebMessageCallback(WebMessageCallback? onMessage) async { + Map args = {}; + args.putIfAbsent('index', () => this._index); + await _webMessageChannel.channel + ?.invokeMethod('setWebMessageCallback', args); + this._onMessage = onMessage; + } + + ///Post a WebMessage to the entangled port. + Future postMessage(WebMessage message) async { + Map args = {}; + args.putIfAbsent('index', () => this._index); + args.putIfAbsent('message', () => message.toMap()); + await _webMessageChannel.channel?.invokeMethod('postMessage', args); + } + + ///Close the message port and free any resources associated with it. + Future close() async { + Map args = {}; + args.putIfAbsent('index', () => this._index); + await _webMessageChannel.channel?.invokeMethod('close', args); + } + + @ExchangeableObjectMethod(toMapMergeWith: true) + // ignore: unused_element + Map _toMapMergeWith() { + return {"index": _index, "webMessageChannelId": _webMessageChannel.id}; + } + + Map toMap() { + return { + "index": this._index, + "webMessageChannelId": this._webMessageChannel.id + }; + } + + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'WebMessagePort{index: $_index}'; + } +} + +extension InternalWebMessagePort on WebMessagePort { + WebMessageCallback? get onMessage => _onMessage; + void set onMessage(WebMessageCallback? value) => _onMessage = value; + + WebMessageChannel get webMessageChannel => _webMessageChannel; + void set webMessageChannel(WebMessageChannel value) => + _webMessageChannel = value; +} diff --git a/lib/src/web_storage/main.dart b/lib/src/web_storage/main.dart index 6462ba4d..c7d1810e 100644 --- a/lib/src/web_storage/main.dart +++ b/lib/src/web_storage/main.dart @@ -1,4 +1,5 @@ export 'web_storage.dart'; +export 'web_storage_item.dart' show WebStorageItem; export 'web_storage_manager.dart'; export 'android/main.dart'; export 'ios/main.dart'; diff --git a/lib/src/web_storage/web_storage.dart b/lib/src/web_storage/web_storage.dart index 56d1121c..28d43a86 100644 --- a/lib/src/web_storage/web_storage.dart +++ b/lib/src/web_storage/web_storage.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import '../in_app_webview/in_app_webview_controller.dart'; import '../types/main.dart'; +import 'web_storage_item.dart'; ///Class that provides access to the JavaScript [Web Storage API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API): `window.sessionStorage` and `window.localStorage`. ///It used by [InAppWebViewController.webStorage]. @@ -27,33 +28,6 @@ class WebStorage { } } -///Class that represents a single web storage item of the JavaScript `window.sessionStorage` and `window.localStorage` objects. -class WebStorageItem { - ///Item key. - String? key; - - ///Item value. - dynamic value; - - WebStorageItem({this.key, this.value}); - - Map toMap() { - return { - "key": key, - "value": value, - }; - } - - Map toJson() { - return this.toMap(); - } - - @override - String toString() { - return toMap().toString(); - } -} - ///Class that provides methods to manage the JavaScript [Storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage) object. ///It is used by [LocalStorage] and [SessionStorage]. class Storage { diff --git a/lib/src/web_storage/web_storage_item.dart b/lib/src/web_storage/web_storage_item.dart new file mode 100644 index 00000000..4a2e3bce --- /dev/null +++ b/lib/src/web_storage/web_storage_item.dart @@ -0,0 +1,15 @@ +import 'package:flutter_inappwebview_internal_annotations/flutter_inappwebview_internal_annotations.dart'; + +part 'web_storage_item.g.dart'; + +///Class that represents a single web storage item of the JavaScript `window.sessionStorage` and `window.localStorage` objects. +@ExchangeableObject() +class WebStorageItem_ { + ///Item key. + String? key; + + ///Item value. + dynamic value; + + WebStorageItem_({this.key, this.value}); +} diff --git a/lib/src/web_storage/web_storage_item.g.dart b/lib/src/web_storage/web_storage_item.g.dart new file mode 100644 index 00000000..ec2f686b --- /dev/null +++ b/lib/src/web_storage/web_storage_item.g.dart @@ -0,0 +1,47 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'web_storage_item.dart'; + +// ************************************************************************** +// ExchangeableObjectGenerator +// ************************************************************************** + +///Class that represents a single web storage item of the JavaScript `window.sessionStorage` and `window.localStorage` objects. +class WebStorageItem { + ///Item key. + String? key; + + ///Item value. + dynamic value; + WebStorageItem({this.key, this.value}); + + ///Gets a possible [WebStorageItem] instance from a [Map] value. + static WebStorageItem? fromMap(Map? map) { + if (map == null) { + return null; + } + final instance = WebStorageItem( + key: map['key'], + value: map['value'], + ); + return instance; + } + + ///Converts instance to a map. + Map toMap() { + return { + "key": key, + "value": value, + }; + } + + ///Converts instance to a map. + Map toJson() { + return toMap(); + } + + @override + String toString() { + return 'WebStorageItem{key: $key, value: $value}'; + } +} diff --git a/macos/Classes/InAppBrowser/InAppBrowserChannelDelegate.swift b/macos/Classes/InAppBrowser/InAppBrowserChannelDelegate.swift index ca9d4d99..7896c2f7 100644 --- a/macos/Classes/InAppBrowser/InAppBrowserChannelDelegate.swift +++ b/macos/Classes/InAppBrowser/InAppBrowserChannelDelegate.swift @@ -18,6 +18,13 @@ public class InAppBrowserChannelDelegate : ChannelDelegate { channel?.invokeMethod("onBrowserCreated", arguments: arguments) } + public func onMenuItemClicked(menuItem: InAppBrowserMenuItem) { + let arguments: [String: Any?] = [ + "id": menuItem.id + ] + channel?.invokeMethod("onMenuItemClicked", arguments: arguments) + } + public func onExit() { let arguments: [String: Any?] = [:] channel?.invokeMethod("onExit", arguments: arguments) diff --git a/macos/Classes/InAppBrowser/InAppBrowserManager.swift b/macos/Classes/InAppBrowser/InAppBrowserManager.swift index 30fe7ca3..b1c21de2 100755 --- a/macos/Classes/InAppBrowser/InAppBrowserManager.swift +++ b/macos/Classes/InAppBrowser/InAppBrowserManager.swift @@ -52,6 +52,7 @@ public class InAppBrowserManager: ChannelDelegate { let settings = arguments["settings"] as! [String: Any?] let windowId = arguments["windowId"] as? Int64 let initialUserScripts = arguments["initialUserScripts"] as? [[String: Any]] + let menuItems = arguments["menuItems"] as! [[String: Any?]] let browserSettings = InAppBrowserSettings() let _ = browserSettings.parse(settings: settings) @@ -78,6 +79,9 @@ public class InAppBrowserManager: ChannelDelegate { let window = InAppBrowserWindow(contentViewController: webViewController) window.browserSettings = browserSettings window.contentViewController = webViewController + for menuItem in menuItems { + window.menuItems.append(InAppBrowserMenuItem.fromMap(map: menuItem)!) + } window.prepare() if #available(macOS 10.12, *), browserSettings.windowType == .tabbed { diff --git a/macos/Classes/InAppBrowser/InAppBrowserSettings.swift b/macos/Classes/InAppBrowser/InAppBrowserSettings.swift index f2c8ab22..25077894 100755 --- a/macos/Classes/InAppBrowser/InAppBrowserSettings.swift +++ b/macos/Classes/InAppBrowser/InAppBrowserSettings.swift @@ -50,6 +50,7 @@ public class InAppBrowserSettings: ISettings { } } var windowFrame: NSRect? + var hideDefaultMenuItems = false override init(){ super.init() diff --git a/macos/Classes/InAppBrowser/InAppBrowserWebViewController.swift b/macos/Classes/InAppBrowser/InAppBrowserWebViewController.swift index 582e02b4..7a287778 100755 --- a/macos/Classes/InAppBrowser/InAppBrowserWebViewController.swift +++ b/macos/Classes/InAppBrowser/InAppBrowserWebViewController.swift @@ -263,6 +263,24 @@ public class InAppBrowserWebViewController: NSViewController, InAppBrowserDelega @objc public func goBackOrForward(steps: Int) { webView?.goBackOrForward(steps: steps) } + + @objc public func onMenuItemClicked(sender: Any?) { + var identifier: String? + if let sender = sender as? NSMenuItem { + identifier = sender.identifier?.rawValue + } + if identifier == nil, let sender = sender as? NSButton { + identifier = sender.identifier?.rawValue + } + if let identifier = identifier, let window = window { + let menuItem = window.menuItems.first { item in + return item.id == Int64(identifier) + } + if let menuItem = menuItem { + channelDelegate?.onMenuItemClicked(menuItem: menuItem) + } + } + } public func setSettings(newSettings: InAppBrowserSettings, newSettingsMap: [String: Any]) { window?.setSettings(newSettings: newSettings, newSettingsMap: newSettingsMap) diff --git a/macos/Classes/InAppBrowser/InAppBrowserWindow.swift b/macos/Classes/InAppBrowser/InAppBrowserWindow.swift index 613e3831..7ef610c2 100644 --- a/macos/Classes/InAppBrowser/InAppBrowserWindow.swift +++ b/macos/Classes/InAppBrowser/InAppBrowserWindow.swift @@ -12,6 +12,7 @@ struct ToolbarIdentifiers { static let backButton = NSToolbarItem.Identifier(rawValue: "BackButton") static let forwardButton = NSToolbarItem.Identifier(rawValue: "ForwardButton") static let reloadButton = NSToolbarItem.Identifier(rawValue: "ReloadButton") + static let menuButton = NSToolbarItem.Identifier(rawValue: "MenuButton") } public class InAppBrowserWindow : NSWindow, NSWindowDelegate, NSToolbarDelegate, NSSearchFieldDelegate { @@ -19,6 +20,8 @@ public class InAppBrowserWindow : NSWindow, NSWindowDelegate, NSToolbarDelegate, var backItem: NSToolbarItem? var forwardItem: NSToolbarItem? var reloadItem: NSToolbarItem? + var menuItem: NSToolbarItem? + var actionItems: [NSToolbarItem] = [] var reloadButton: NSButton? { get { @@ -44,8 +47,14 @@ public class InAppBrowserWindow : NSWindow, NSWindowDelegate, NSToolbarDelegate, } } } + var menuButton: NSPopUpButton? { + get { + return menuItem?.view as? NSPopUpButton + } + } var browserSettings: InAppBrowserSettings? + var menuItems: [InAppBrowserMenuItem] = [] public func prepare() { title = "" @@ -119,6 +128,45 @@ public class InAppBrowserWindow : NSWindow, NSWindowDelegate, NSToolbarDelegate, } } + if #available(macOS 10.15, *), !menuItems.isEmpty { + menuItem = NSMenuToolbarItem(itemIdentifier: ToolbarIdentifiers.menuButton) + if let menuItem = menuItem as? NSMenuToolbarItem { + menuItem.label = "" + if #available(macOS 11.0, *) { + menuItem.image = NSImage(systemSymbolName: "ellipsis.circle", + accessibilityDescription: "Options") + menuItem.showsIndicator = true + menuItem.isBordered = true + } else { + menuItem.title = "Options" + } + let menu = NSMenu() + menuItems = menuItems.sorted(by: {$0.order ?? 0 < $1.order ?? 0}) + for item in menuItems { + if !item.showAsAction { + let nsItem = NSMenuItem(title: item.title, action: #selector(InAppBrowserWebViewController.onMenuItemClicked), keyEquivalent: "") + nsItem.identifier = NSUserInterfaceItemIdentifier.init(String(item.id)) + nsItem.image = item.icon + menu.addItem(nsItem) + } else { + let actionItem = NSMenuToolbarItem(itemIdentifier: NSToolbarItem.Identifier(rawValue: String(item.id))) + actionItem.label = "" + if let webViewController = contentViewController as? InAppBrowserWebViewController { + let actionButton = NSButton(title: item.title, + target: webViewController, + action: #selector(InAppBrowserWebViewController.onMenuItemClicked)) + actionButton.identifier = NSUserInterfaceItemIdentifier.init(String(item.id)) + actionButton.image = item.icon + actionItem.view = actionButton + } + actionItems.append(actionItem) + } + } + menuItem.menu = menu + } + } + + if #available(macOS 10.14, *) { windowToolbar.centeredItemIdentifier = ToolbarIdentifiers.searchBar } @@ -158,24 +206,34 @@ public class InAppBrowserWindow : NSWindow, NSWindowDelegate, NSToolbarDelegate, if let windowFrame = browserSettings.windowFrame { setFrame(windowFrame, display: true) } + reloadItem?.view?.isHidden = browserSettings.hideDefaultMenuItems + backItem?.view?.isHidden = browserSettings.hideDefaultMenuItems + forwardItem?.view?.isHidden = browserSettings.hideDefaultMenuItems } } public func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { - return [ ToolbarIdentifiers.searchBar, + return [[ ToolbarIdentifiers.menuButton, + ToolbarIdentifiers.searchBar, ToolbarIdentifiers.backButton, ToolbarIdentifiers.forwardButton, ToolbarIdentifiers.reloadButton, - .flexibleSpace ] + .flexibleSpace ], actionItems.compactMap({ item in + return item.itemIdentifier + })].flatMap { $0 } } public func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { - return [.flexibleSpace, + return [[.flexibleSpace, ToolbarIdentifiers.searchBar, .flexibleSpace, ToolbarIdentifiers.reloadButton, ToolbarIdentifiers.backButton, - ToolbarIdentifiers.forwardButton] + ToolbarIdentifiers.forwardButton], + actionItems.compactMap({ item in + return item.itemIdentifier + }), + [ToolbarIdentifiers.menuButton]].flatMap { $0 } } public func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? { @@ -188,8 +246,13 @@ public class InAppBrowserWindow : NSWindow, NSWindowDelegate, NSToolbarDelegate, return forwardItem case ToolbarIdentifiers.reloadButton: return reloadItem + case ToolbarIdentifiers.menuButton: + return menuItem default: - return nil + let actionItem = actionItems.first { item in + return item.itemIdentifier == itemIdentifier + } + return actionItem } } @@ -273,6 +336,11 @@ public class InAppBrowserWindow : NSWindow, NSWindowDelegate, NSToolbarDelegate, if newSettingsMap["windowFrame"] != nil, browserSettings?.windowFrame != newSettings.windowFrame { setFrame(newSettings.windowFrame!, display: true) } + if newSettingsMap["hideDefaultMenuItems"] != nil, browserSettings?.hideDefaultMenuItems != newSettings.hideDefaultMenuItems { + reloadItem?.view?.isHidden = newSettings.hideDefaultMenuItems + backItem?.view?.isHidden = newSettings.hideDefaultMenuItems + forwardItem?.view?.isHidden = newSettings.hideDefaultMenuItems + } browserSettings = newSettings } diff --git a/macos/Classes/Types/InAppBrowserMenuItem.swift b/macos/Classes/Types/InAppBrowserMenuItem.swift new file mode 100644 index 00000000..beeee486 --- /dev/null +++ b/macos/Classes/Types/InAppBrowserMenuItem.swift @@ -0,0 +1,49 @@ +// +// InAppBrowserMenuItem.swift +// flutter_inappwebview +// +// Created by Lorenzo Pichilli on 23/05/23. +// + +import Foundation +import FlutterMacOS + +public class InAppBrowserMenuItem: NSObject { + var id: Int64 + var title: String + var order: Int64? + var icon: NSImage? + var iconColor: NSColor? + var showAsAction = false + + public init(id: Int64, title: String, order: Int64?, icon: NSImage?, iconColor: NSColor?, showAsAction: Bool) { + self.id = id + self.title = title + self.order = order + self.icon = icon + self.iconColor = iconColor + self.showAsAction = showAsAction + if let icon = icon, let iconColor = iconColor { + self.icon = icon.tint(color: iconColor) + } + } + + public static func fromMap(map: [String:Any?]?) -> InAppBrowserMenuItem? { + guard let map = map else { + return nil + } + let id = map["id"] as! Int64 + let title = map["title"] as! String + let order = map["order"] as? Int64 + var icon = NSImage.fromMap(map: map["icon"] as? [String : Any?]) + if let data = map["icon"] as? FlutterStandardTypedData { + icon = NSImage(data: data.data) + } + var iconColor: NSColor? = nil + if let hexString = map["iconColor"] as? String { + iconColor = NSColor(hexString: hexString) + } + let showAsAction = map["showAsAction"] as! Bool + return InAppBrowserMenuItem(id: id, title: title, order: order, icon: icon, iconColor: iconColor, showAsAction: showAsAction) + } +} diff --git a/macos/Classes/Types/NSImage.swift b/macos/Classes/Types/NSImage.swift new file mode 100644 index 00000000..096a4cea --- /dev/null +++ b/macos/Classes/Types/NSImage.swift @@ -0,0 +1,36 @@ +// +// NSImage.swift +// flutter_inappwebview +// +// Created by Lorenzo Pichilli on 23/05/23. +// + +import Foundation +import FlutterMacOS + +extension NSImage { + public static func fromMap(map: [String:Any?]?) -> NSImage? { + guard let map = map else { + return nil + } + if let name = map["name"] as? String { + return NSImage(named: name) + } + if #available(macOS 11.0, *), let systemName = map["systemName"] as? String { + return NSImage(systemSymbolName: systemName, accessibilityDescription: nil) + } + if let data = map["data"] as? FlutterStandardTypedData { + return NSImage(data: data.data) + } + return nil + } + + func tint(color: NSColor) -> NSImage { + return NSImage(size: size, flipped: false) { (rect) -> Bool in + color.set() + rect.fill() + self.draw(in: rect, from: NSRect(origin: .zero, size: self.size), operation: .destinationIn, fraction: 1.0) + return true + } + } +}