@capgo/capacitor-inappbrowser 8.7.9 → 8.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/CapgoInAppBrowserPlugin.java +40 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/Options.java +40 -16
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewCallbacks.java +2 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java +163 -12
- package/dist/docs.json +126 -0
- package/dist/esm/definitions.d.ts +68 -0
- package/dist/esm/definitions.js +11 -0
- package/dist/esm/definitions.js.map +1 -1
- package/dist/plugin.cjs.js +11 -0
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +11 -0
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift +103 -86
- package/ios/Sources/InAppBrowserPlugin/WKWebViewController.swift +71 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -148,6 +148,34 @@ await InAppBrowser.hide({ id: first.id });
|
|
|
148
148
|
await InAppBrowser.show({ id: second.id });
|
|
149
149
|
```
|
|
150
150
|
|
|
151
|
+
#### Hide from the native close button and brand the toolbar title
|
|
152
|
+
|
|
153
|
+
Use `closeAction: CloseAction.HIDE` when the toolbar close button should hide the WebView instead of destroying it. Listen to `hideEvent` if your app needs to update Ionic state, then call `show()` later to bring the same browser session back.
|
|
154
|
+
|
|
155
|
+
```js
|
|
156
|
+
import { CloseAction, InAppBrowser } from '@capgo/capacitor-inappbrowser';
|
|
157
|
+
|
|
158
|
+
await InAppBrowser.addListener('hideEvent', ({ id, url }) => {
|
|
159
|
+
console.log('Browser hidden', id, url);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const { id } = await InAppBrowser.openWebView({
|
|
163
|
+
url: 'https://example.com/checkout',
|
|
164
|
+
title: 'Secure checkout',
|
|
165
|
+
closeAction: CloseAction.HIDE,
|
|
166
|
+
titleFontFamily: 'Inter',
|
|
167
|
+
titleIcon: {
|
|
168
|
+
ios: { iconType: 'sf-symbol', icon: 'lock.fill' },
|
|
169
|
+
android: { iconType: 'vector', icon: 'ic_lock', width: 20, height: 20 },
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Later, after the toolbar close button hides it:
|
|
174
|
+
await InAppBrowser.show({ id });
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
For iOS, `titleFontFamily` must match a registered font family name and `titleIcon` can use either an SF Symbol or bundled asset. For Android, `titleFontFamily` first checks `res/font` and then falls back to a system font family; `titleIcon` can use a vector drawable or bundled SVG asset.
|
|
178
|
+
|
|
151
179
|
#### Embed advanced web app flows
|
|
152
180
|
|
|
153
181
|
Use proxy rules and `handleDownloads` for web apps that need request control, file uploads, downloads, or controlled popup behavior inside the managed browser. Typical examples include document portals, support desks, payment pages, Google Pay flows on Android, and apps that need to keep `_blank` links inside the same managed WebView.
|
|
@@ -520,6 +548,7 @@ The W3C Payment Request API (used by Google Pay) requires Android WebView 120+.
|
|
|
520
548
|
* [`addListener('urlChangeEvent', ...)`](#addlistenerurlchangeevent-)
|
|
521
549
|
* [`addListener('buttonNearDoneClick', ...)`](#addlistenerbuttonneardoneclick-)
|
|
522
550
|
* [`addListener('closeEvent', ...)`](#addlistenercloseevent-)
|
|
551
|
+
* [`addListener('hideEvent', ...)`](#addlistenerhideevent-)
|
|
523
552
|
* [`addListener('confirmBtnClicked', ...)`](#addlistenerconfirmbtnclicked-)
|
|
524
553
|
* [`addListener('messageFromWebview', ...)`](#addlistenermessagefromwebview-)
|
|
525
554
|
* [`addListener('screenshotTaken', ...)`](#addlistenerscreenshottaken-)
|
|
@@ -943,6 +972,26 @@ Listen for close click only for openWebView
|
|
|
943
972
|
--------------------
|
|
944
973
|
|
|
945
974
|
|
|
975
|
+
### addListener('hideEvent', ...)
|
|
976
|
+
|
|
977
|
+
```typescript
|
|
978
|
+
addListener(eventName: 'hideEvent', listenerFunc: UrlChangeListener) => Promise<PluginListenerHandle>
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
Listen for webviews hidden by the toolbar close button when closeAction is <a href="#closeaction">CloseAction.HIDE</a>.
|
|
982
|
+
|
|
983
|
+
| Param | Type |
|
|
984
|
+
| ------------------ | --------------------------------------------------------------- |
|
|
985
|
+
| **`eventName`** | <code>'hideEvent'</code> |
|
|
986
|
+
| **`listenerFunc`** | <code><a href="#urlchangelistener">UrlChangeListener</a></code> |
|
|
987
|
+
|
|
988
|
+
**Returns:** <code>Promise<<a href="#pluginlistenerhandle">PluginListenerHandle</a>></code>
|
|
989
|
+
|
|
990
|
+
**Since:** 8.7.7
|
|
991
|
+
|
|
992
|
+
--------------------
|
|
993
|
+
|
|
994
|
+
|
|
946
995
|
### addListener('confirmBtnClicked', ...)
|
|
947
996
|
|
|
948
997
|
```typescript
|
|
@@ -1430,6 +1479,8 @@ And in the AndroidManifest.xml file:
|
|
|
1430
1479
|
| **`toolbarType`** | <code><a href="#toolbartype">ToolBarType</a></code> | Toolbar type determines the appearance and behavior of the browser's toolbar - "activity": Shows a simple toolbar with just a close button and share button - "navigation": Shows a full navigation toolbar with back/forward buttons - "blank": Shows no toolbar - "": Default toolbar with close button | <code>ToolBarType.DEFAULT</code> | 0.1.0 |
|
|
1431
1480
|
| **`shareSubject`** | <code>string</code> | Subject text for sharing. Required when using shareDisclaimer. This text will be used as the subject line when sharing content. | | 0.1.0 |
|
|
1432
1481
|
| **`title`** | <code>string</code> | Title of the browser | <code>"New Window"</code> | 0.1.0 |
|
|
1482
|
+
| **`titleFontFamily`** | <code>string</code> | Native toolbar title font family. On iOS, use the registered font family name. On Android, the plugin first tries a res/font resource name, then falls back to a system font family name. | | 8.7.7 |
|
|
1483
|
+
| **`titleIcon`** | <code><a href="#toolbartitleiconoptions">ToolbarTitleIconOptions</a></code> | Native toolbar title icon displayed before the title text. For Android: - iconType can be "asset" for a bundled SVG asset or "vector" for a drawable resource - icon path should be in the public folder for assets (e.g. "brand.svg") - width and height are optional and default to 24dp For iOS: - iconType can be "sf-symbol" or "asset" - for sf-symbol, icon should be the symbol name - for asset, icon should be the asset name or bundled web asset path | | 8.7.7 |
|
|
1433
1484
|
| **`backgroundColor`** | <code><a href="#backgroundcolor">BackgroundColor</a></code> | Background color of the browser | <code>BackgroundColor.BLACK</code> | 0.1.0 |
|
|
1434
1485
|
| **`activeNativeNavigationForWebview`** | <code>boolean</code> | If true, enables native navigation gestures within the webview. - Android: Native back button navigates within webview history - iOS: Enables swipe left/right gestures for back/forward navigation | <code>false (Android), true (iOS - enabled by default)</code> | |
|
|
1435
1486
|
| **`disableGoBackOnNativeApplication`** | <code>boolean</code> | Disable the possibility to go back on native application, useful to force user to stay on the webview, Android only | <code>false</code> | |
|
|
@@ -1437,6 +1488,7 @@ And in the AndroidManifest.xml file:
|
|
|
1437
1488
|
| **`isInspectable`** | <code>boolean</code> | Whether the website in the webview is inspectable or not, ios only | <code>false</code> | |
|
|
1438
1489
|
| **`isAnimated`** | <code>boolean</code> | Whether the webview opening is animated or not, ios only | <code>true</code> | |
|
|
1439
1490
|
| **`showReloadButton`** | <code>boolean</code> | Shows a reload button that reloads the web page | <code>false</code> | 1.0.15 |
|
|
1491
|
+
| **`closeAction`** | <code><a href="#closeaction">CloseAction</a></code> | closeAction controls what happens when the native toolbar close button is pressed. This does not change the behavior of close(), JavaScript window.mobileApp.close(), or native back navigation. | <code>CloseAction.CLOSE</code> | 8.7.7 |
|
|
1440
1492
|
| **`closeModal`** | <code>boolean</code> | CloseModal: if true a confirm will be displayed when user clicks on close button, if false the browser will be closed immediately. | <code>false</code> | 1.1.0 |
|
|
1441
1493
|
| **`closeModalTitle`** | <code>string</code> | CloseModalTitle: title of the confirm when user clicks on close button | <code>"Close"</code> | 1.1.0 |
|
|
1442
1494
|
| **`closeModalDescription`** | <code>string</code> | CloseModalDescription: description of the confirm when user clicks on close button | <code>"Are you sure you want to close this window?"</code> | 1.1.0 |
|
|
@@ -1498,6 +1550,14 @@ And in the AndroidManifest.xml file:
|
|
|
1498
1550
|
| **`cancelBtn`** | <code>string</code> | Text for the cancel button | <code>"Cancel"</code> |
|
|
1499
1551
|
|
|
1500
1552
|
|
|
1553
|
+
#### ToolbarTitleIconOptions
|
|
1554
|
+
|
|
1555
|
+
| Prop | Type |
|
|
1556
|
+
| ------------- | ---------------------------------------------------------------------------------------------- |
|
|
1557
|
+
| **`ios`** | <code>{ iconType: 'sf-symbol' \| 'asset'; icon: string; }</code> |
|
|
1558
|
+
| **`android`** | <code>{ iconType: 'asset' \| 'vector'; icon: string; width?: number; height?: number; }</code> |
|
|
1559
|
+
|
|
1560
|
+
|
|
1501
1561
|
#### NativeProxyRule
|
|
1502
1562
|
|
|
1503
1563
|
Native-first proxy rule used on Android and iOS.
|
|
@@ -1815,6 +1875,14 @@ Native handling mode used after a managed download finishes.
|
|
|
1815
1875
|
| **`BLACK`** | <code>'black'</code> |
|
|
1816
1876
|
|
|
1817
1877
|
|
|
1878
|
+
#### CloseAction
|
|
1879
|
+
|
|
1880
|
+
| Members | Value | Description |
|
|
1881
|
+
| ----------- | -------------------- | -------------------------------------------------------------------- |
|
|
1882
|
+
| **`CLOSE`** | <code>'close'</code> | The toolbar close button closes and destroys the webview. |
|
|
1883
|
+
| **`HIDE`** | <code>'hide'</code> | The toolbar close button hides the webview so it can be shown again. |
|
|
1884
|
+
|
|
1885
|
+
|
|
1818
1886
|
#### InvisibilityMode
|
|
1819
1887
|
|
|
1820
1888
|
| Members | Value | Description |
|
|
@@ -48,6 +48,7 @@ import java.util.Deque;
|
|
|
48
48
|
import java.util.HashMap;
|
|
49
49
|
import java.util.Iterator;
|
|
50
50
|
import java.util.List;
|
|
51
|
+
import java.util.Locale;
|
|
51
52
|
import java.util.Map;
|
|
52
53
|
import java.util.UUID;
|
|
53
54
|
import java.util.concurrent.ExecutorService;
|
|
@@ -168,6 +169,11 @@ public class CapgoInAppBrowserPlugin extends Plugin implements WebViewDialog.Per
|
|
|
168
169
|
unregisterWebView(webViewId);
|
|
169
170
|
}
|
|
170
171
|
|
|
172
|
+
@Override
|
|
173
|
+
public void hideEvent(String url) {
|
|
174
|
+
notifyListeners("hideEvent", new JSObject().put("id", webViewId).put("url", url));
|
|
175
|
+
}
|
|
176
|
+
|
|
171
177
|
@Override
|
|
172
178
|
public void pageLoaded() {
|
|
173
179
|
notifyListeners("browserPageLoaded", new JSObject().put("id", webViewId));
|
|
@@ -1020,6 +1026,40 @@ public class CapgoInAppBrowserPlugin extends Plugin implements WebViewDialog.Per
|
|
|
1020
1026
|
options.setToolbarColor(call.getString("toolbarColor", "#ffffff"));
|
|
1021
1027
|
options.setBackgroundColor(call.getString("backgroundColor", "white"));
|
|
1022
1028
|
options.setToolbarTextColor(call.getString("toolbarTextColor"));
|
|
1029
|
+
String closeAction = call.getString("closeAction", "close").toLowerCase(Locale.ROOT);
|
|
1030
|
+
if (!"close".equals(closeAction) && !"hide".equals(closeAction)) {
|
|
1031
|
+
call.reject("closeAction must be 'close' or 'hide'");
|
|
1032
|
+
return;
|
|
1033
|
+
}
|
|
1034
|
+
options.setCloseAction(closeAction);
|
|
1035
|
+
options.setTitleFontFamily(call.getString("titleFontFamily"));
|
|
1036
|
+
JSObject titleIconObj = call.getObject("titleIcon");
|
|
1037
|
+
if (titleIconObj != null) {
|
|
1038
|
+
JSObject androidTitleIconObj = titleIconObj.getJSObject("android");
|
|
1039
|
+
if (androidTitleIconObj != null) {
|
|
1040
|
+
try {
|
|
1041
|
+
String titleIconType = androidTitleIconObj.getString("iconType", "asset");
|
|
1042
|
+
String titleIconName = androidTitleIconObj.getString("icon", "");
|
|
1043
|
+
if ("vector".equals(titleIconType)) {
|
|
1044
|
+
int resourceId = getContext()
|
|
1045
|
+
.getResources()
|
|
1046
|
+
.getIdentifier(titleIconName, "drawable", getContext().getPackageName());
|
|
1047
|
+
if (resourceId == 0) {
|
|
1048
|
+
Log.e("InAppBrowser", "Title icon vector resource not found: " + titleIconName);
|
|
1049
|
+
call.reject("titleIcon validation failed: vector resource not found: " + titleIconName);
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
options.setTitleIcon(
|
|
1054
|
+
Options.ButtonNearDone.generateFromAndroidObject(androidTitleIconObj, getContext().getAssets(), "titleIcon.android")
|
|
1055
|
+
);
|
|
1056
|
+
} catch (Exception e) {
|
|
1057
|
+
Log.e("InAppBrowser", "Error setting titleIcon: " + e.getMessage(), e);
|
|
1058
|
+
call.reject("titleIcon validation failed: " + e.getMessage());
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1023
1063
|
options.setArrow(Boolean.TRUE.equals(call.getBoolean("showArrow", false)));
|
|
1024
1064
|
options.setIgnoreUntrustedSSLError(Boolean.TRUE.equals(call.getBoolean("ignoreUntrustedSSLError", false)));
|
|
1025
1065
|
options.setClientCertificatePrompt(resolveClientCertificatePrompt(call));
|
|
@@ -57,7 +57,6 @@ public class Options {
|
|
|
57
57
|
throws IllegalArgumentException, RuntimeException {
|
|
58
58
|
JSObject buttonNearDone = call.getObject("buttonNearDone");
|
|
59
59
|
if (buttonNearDone == null) {
|
|
60
|
-
// Return null when "buttonNearDone" isn't configured, else throw an error
|
|
61
60
|
return null;
|
|
62
61
|
}
|
|
63
62
|
|
|
@@ -66,42 +65,41 @@ public class Options {
|
|
|
66
65
|
throw new IllegalArgumentException("buttonNearDone.android is null");
|
|
67
66
|
}
|
|
68
67
|
|
|
68
|
+
return generateFromAndroidObject(android, assetManager, "buttonNearDone.android");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public static ButtonNearDone generateFromAndroidObject(JSObject android, AssetManager assetManager, String optionName)
|
|
72
|
+
throws IllegalArgumentException, RuntimeException {
|
|
69
73
|
String iconType = android.getString("iconType", "asset");
|
|
70
74
|
AllIconTypes iconTypeEnum;
|
|
71
75
|
|
|
72
|
-
// Validate and process icon type
|
|
73
76
|
if ("asset".equals(iconType)) {
|
|
74
77
|
iconTypeEnum = AllIconTypes.ASSET;
|
|
75
78
|
} else if ("vector".equals(iconType)) {
|
|
76
79
|
iconTypeEnum = AllIconTypes.VECTOR;
|
|
77
80
|
} else {
|
|
78
|
-
throw new IllegalArgumentException("
|
|
81
|
+
throw new IllegalArgumentException(optionName + ".iconType must be 'asset' or 'vector'");
|
|
79
82
|
}
|
|
80
83
|
|
|
81
84
|
String icon = android.getString("icon");
|
|
82
85
|
if (icon == null) {
|
|
83
|
-
throw new IllegalArgumentException("
|
|
86
|
+
throw new IllegalArgumentException(optionName + ".icon is null");
|
|
84
87
|
}
|
|
85
88
|
|
|
86
|
-
// For asset type, verify the file exists
|
|
87
89
|
if (iconTypeEnum == AllIconTypes.ASSET) {
|
|
88
90
|
InputStream fileInputString = null;
|
|
89
91
|
|
|
90
92
|
try {
|
|
91
|
-
// Try to find in public folder first
|
|
92
93
|
try {
|
|
93
94
|
fileInputString = assetManager.open("public/" + icon);
|
|
94
95
|
} catch (IOException e) {
|
|
95
|
-
// If not in public, try in root assets
|
|
96
96
|
try {
|
|
97
97
|
fileInputString = assetManager.open(icon);
|
|
98
98
|
} catch (IOException e2) {
|
|
99
|
-
throw new IllegalArgumentException("
|
|
99
|
+
throw new IllegalArgumentException(optionName + ".icon cannot be found in the assetManager", e2);
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
|
-
// File exists, do nothing
|
|
103
102
|
} finally {
|
|
104
|
-
// Close the input stream if it was opened
|
|
105
103
|
if (fileInputString != null) {
|
|
106
104
|
try {
|
|
107
105
|
fileInputString.close();
|
|
@@ -110,18 +108,14 @@ public class Options {
|
|
|
110
108
|
}
|
|
111
109
|
}
|
|
112
110
|
}
|
|
113
|
-
}
|
|
114
|
-
// For vector type, we don't validate here since resources are checked at runtime
|
|
115
|
-
else if (iconTypeEnum == AllIconTypes.VECTOR) {
|
|
116
|
-
// Vector resources will be validated when used
|
|
111
|
+
} else if (iconTypeEnum == AllIconTypes.VECTOR) {
|
|
117
112
|
System.out.println("Vector resource will be validated at runtime: " + icon);
|
|
118
113
|
}
|
|
119
114
|
|
|
120
115
|
Integer width = android.getInteger("width", 24);
|
|
121
116
|
Integer height = android.getInteger("height", 24);
|
|
122
117
|
|
|
123
|
-
|
|
124
|
-
return buttonNearDone1;
|
|
118
|
+
return new ButtonNearDone(iconTypeEnum, iconType, icon, height, width);
|
|
125
119
|
}
|
|
126
120
|
|
|
127
121
|
public AllIconTypes getIconTypeEnum() {
|
|
@@ -151,6 +145,9 @@ public class Options {
|
|
|
151
145
|
private String CloseModalDescription;
|
|
152
146
|
private String CloseModalCancel;
|
|
153
147
|
private ButtonNearDone buttonNearDone;
|
|
148
|
+
private String closeAction = "close";
|
|
149
|
+
private String titleFontFamily;
|
|
150
|
+
private ButtonNearDone titleIcon;
|
|
154
151
|
private String CloseModalOk;
|
|
155
152
|
private Pattern closeModalURLPattern;
|
|
156
153
|
private String url;
|
|
@@ -418,6 +415,30 @@ public class Options {
|
|
|
418
415
|
return this.buttonNearDone;
|
|
419
416
|
}
|
|
420
417
|
|
|
418
|
+
public String getCloseAction() {
|
|
419
|
+
return closeAction;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
public void setCloseAction(String closeAction) {
|
|
423
|
+
this.closeAction = closeAction;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
public String getTitleFontFamily() {
|
|
427
|
+
return titleFontFamily;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
public void setTitleFontFamily(String titleFontFamily) {
|
|
431
|
+
this.titleFontFamily = titleFontFamily;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
public ButtonNearDone getTitleIcon() {
|
|
435
|
+
return titleIcon;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
public void setTitleIcon(ButtonNearDone titleIcon) {
|
|
439
|
+
this.titleIcon = titleIcon;
|
|
440
|
+
}
|
|
441
|
+
|
|
421
442
|
public String getCloseModalCancel() {
|
|
422
443
|
return CloseModalCancel;
|
|
423
444
|
}
|
|
@@ -713,6 +734,9 @@ public class Options {
|
|
|
713
734
|
copy.setCloseModalOk(CloseModalOk);
|
|
714
735
|
copy.setCloseModalURLPattern(closeModalURLPattern);
|
|
715
736
|
copy.setButtonNearDone(buttonNearDone);
|
|
737
|
+
copy.setCloseAction(closeAction);
|
|
738
|
+
copy.setTitleFontFamily(titleFontFamily);
|
|
739
|
+
copy.setTitleIcon(titleIcon);
|
|
716
740
|
copy.setUrl("about:blank");
|
|
717
741
|
copy.setHeaders(headers);
|
|
718
742
|
copy.setCredentials(credentials);
|
|
@@ -16,6 +16,8 @@ import android.graphics.Color;
|
|
|
16
16
|
import android.graphics.Paint;
|
|
17
17
|
import android.graphics.PorterDuff;
|
|
18
18
|
import android.graphics.PorterDuffColorFilter;
|
|
19
|
+
import android.graphics.Typeface;
|
|
20
|
+
import android.graphics.drawable.BitmapDrawable;
|
|
19
21
|
import android.graphics.drawable.ColorDrawable;
|
|
20
22
|
import android.graphics.drawable.Drawable;
|
|
21
23
|
import android.net.Uri;
|
|
@@ -69,6 +71,7 @@ import androidx.activity.result.ActivityResult;
|
|
|
69
71
|
import androidx.activity.result.contract.ActivityResultContracts;
|
|
70
72
|
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
|
71
73
|
import androidx.core.content.FileProvider;
|
|
74
|
+
import androidx.core.content.res.ResourcesCompat;
|
|
72
75
|
import androidx.core.graphics.Insets;
|
|
73
76
|
import androidx.core.view.ViewCompat;
|
|
74
77
|
import androidx.core.view.WindowInsetsCompat;
|
|
@@ -344,6 +347,10 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
344
347
|
private final Map<String, BlobDownloadSession> blobDownloadSessions = new ConcurrentHashMap<>();
|
|
345
348
|
private final Map<String, ClientCertificateIdentity> clientCertificateIdentities = new ConcurrentHashMap<>();
|
|
346
349
|
private int iconColor = Color.BLACK; // Default icon color
|
|
350
|
+
private Typeface cachedTitleTypeface;
|
|
351
|
+
private String cachedTitleFontFamily;
|
|
352
|
+
private Drawable cachedTitleIconDrawable;
|
|
353
|
+
private boolean cachedTitleIconResolved;
|
|
347
354
|
private boolean isHiddenModeActive = false;
|
|
348
355
|
private WindowManager.LayoutParams previousWindowAttributes;
|
|
349
356
|
private Drawable previousWindowBackground;
|
|
@@ -3863,6 +3870,156 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
3863
3870
|
} else {
|
|
3864
3871
|
textView.setText("");
|
|
3865
3872
|
}
|
|
3873
|
+
applyTitleTextOptions(textView);
|
|
3874
|
+
}
|
|
3875
|
+
|
|
3876
|
+
private void performToolbarCloseAction(String currentUrl) {
|
|
3877
|
+
if (_options != null && "hide".equals(_options.getCloseAction())) {
|
|
3878
|
+
setHidden(true);
|
|
3879
|
+
if (_options.getCallbacks() != null) {
|
|
3880
|
+
_options.getCallbacks().hideEvent(currentUrl);
|
|
3881
|
+
}
|
|
3882
|
+
return;
|
|
3883
|
+
}
|
|
3884
|
+
|
|
3885
|
+
dismiss();
|
|
3886
|
+
if (_options != null && _options.getCallbacks() != null) {
|
|
3887
|
+
_options.getCallbacks().closeEvent(currentUrl);
|
|
3888
|
+
}
|
|
3889
|
+
}
|
|
3890
|
+
|
|
3891
|
+
private void applyTitleTextOptions(TextView titleText) {
|
|
3892
|
+
if (titleText == null || _options == null) {
|
|
3893
|
+
return;
|
|
3894
|
+
}
|
|
3895
|
+
|
|
3896
|
+
String fontFamily = _options.getTitleFontFamily();
|
|
3897
|
+
if (!TextUtils.isEmpty(fontFamily)) {
|
|
3898
|
+
if (!fontFamily.equals(cachedTitleFontFamily)) {
|
|
3899
|
+
cachedTitleFontFamily = fontFamily;
|
|
3900
|
+
cachedTitleTypeface = resolveTitleTypeface(fontFamily);
|
|
3901
|
+
}
|
|
3902
|
+
if (cachedTitleTypeface != null) {
|
|
3903
|
+
titleText.setTypeface(cachedTitleTypeface);
|
|
3904
|
+
}
|
|
3905
|
+
} else {
|
|
3906
|
+
cachedTitleFontFamily = null;
|
|
3907
|
+
cachedTitleTypeface = null;
|
|
3908
|
+
}
|
|
3909
|
+
|
|
3910
|
+
Options.ButtonNearDone titleIcon = _options.getTitleIcon();
|
|
3911
|
+
if (titleIcon == null) {
|
|
3912
|
+
titleText.setCompoundDrawablesRelative(null, null, null, null);
|
|
3913
|
+
cachedTitleIconDrawable = null;
|
|
3914
|
+
cachedTitleIconResolved = false;
|
|
3915
|
+
return;
|
|
3916
|
+
}
|
|
3917
|
+
|
|
3918
|
+
if (!cachedTitleIconResolved) {
|
|
3919
|
+
cachedTitleIconDrawable = loadTitleIconDrawable(titleIcon);
|
|
3920
|
+
cachedTitleIconResolved = true;
|
|
3921
|
+
}
|
|
3922
|
+
|
|
3923
|
+
if (cachedTitleIconDrawable != null) {
|
|
3924
|
+
titleText.setCompoundDrawablesRelative(cachedTitleIconDrawable, null, null, null);
|
|
3925
|
+
titleText.setCompoundDrawablePadding(Math.round(6 * _context.getResources().getDisplayMetrics().density));
|
|
3926
|
+
} else {
|
|
3927
|
+
titleText.setCompoundDrawablesRelative(null, null, null, null);
|
|
3928
|
+
}
|
|
3929
|
+
}
|
|
3930
|
+
|
|
3931
|
+
private Typeface resolveTitleTypeface(String fontFamily) {
|
|
3932
|
+
try {
|
|
3933
|
+
int fontResourceId = _context.getResources().getIdentifier(fontFamily, "font", _context.getPackageName());
|
|
3934
|
+
if (fontResourceId != 0) {
|
|
3935
|
+
Typeface typeface = ResourcesCompat.getFont(_context, fontResourceId);
|
|
3936
|
+
if (typeface != null) {
|
|
3937
|
+
return typeface;
|
|
3938
|
+
}
|
|
3939
|
+
}
|
|
3940
|
+
return Typeface.create(fontFamily, Typeface.NORMAL);
|
|
3941
|
+
} catch (Exception e) {
|
|
3942
|
+
Log.e("InAppBrowser", "Error loading title font: " + e.getMessage());
|
|
3943
|
+
return Typeface.create(fontFamily, Typeface.NORMAL);
|
|
3944
|
+
}
|
|
3945
|
+
}
|
|
3946
|
+
|
|
3947
|
+
private Drawable loadTitleIconDrawable(Options.ButtonNearDone titleIcon) {
|
|
3948
|
+
int width = Math.round(
|
|
3949
|
+
(titleIcon.getWidth() > 0 ? titleIcon.getWidth() : 24) * _context.getResources().getDisplayMetrics().density
|
|
3950
|
+
);
|
|
3951
|
+
int height = Math.round(
|
|
3952
|
+
(titleIcon.getHeight() > 0 ? titleIcon.getHeight() : 24) * _context.getResources().getDisplayMetrics().density
|
|
3953
|
+
);
|
|
3954
|
+
|
|
3955
|
+
if ("vector".equals(titleIcon.getIconType())) {
|
|
3956
|
+
try {
|
|
3957
|
+
String iconName = titleIcon.getIcon();
|
|
3958
|
+
if (iconName.endsWith(".xml")) {
|
|
3959
|
+
iconName = iconName.substring(0, iconName.length() - 4);
|
|
3960
|
+
}
|
|
3961
|
+
int resourceId = _context.getResources().getIdentifier(iconName, "drawable", _context.getPackageName());
|
|
3962
|
+
if (resourceId == 0) {
|
|
3963
|
+
Log.e("InAppBrowser", "Title icon vector drawable not found: " + iconName);
|
|
3964
|
+
return null;
|
|
3965
|
+
}
|
|
3966
|
+
Drawable drawable = ResourcesCompat.getDrawable(_context.getResources(), resourceId, _context.getTheme());
|
|
3967
|
+
if (drawable == null) {
|
|
3968
|
+
return null;
|
|
3969
|
+
}
|
|
3970
|
+
drawable = drawable.mutate();
|
|
3971
|
+
drawable.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN);
|
|
3972
|
+
drawable.setBounds(0, 0, width, height);
|
|
3973
|
+
return drawable;
|
|
3974
|
+
} catch (Exception e) {
|
|
3975
|
+
Log.e("InAppBrowser", "Error loading title vector icon: " + e.getMessage());
|
|
3976
|
+
return null;
|
|
3977
|
+
}
|
|
3978
|
+
}
|
|
3979
|
+
|
|
3980
|
+
if ("asset".equals(titleIcon.getIconType())) {
|
|
3981
|
+
InputStream inputStream = null;
|
|
3982
|
+
try {
|
|
3983
|
+
AssetManager assetManager = _context.getAssets();
|
|
3984
|
+
try {
|
|
3985
|
+
inputStream = assetManager.open("public/" + titleIcon.getIcon());
|
|
3986
|
+
} catch (IOException e) {
|
|
3987
|
+
inputStream = assetManager.open(titleIcon.getIcon());
|
|
3988
|
+
}
|
|
3989
|
+
|
|
3990
|
+
SVG svg = SVG.getFromInputStream(inputStream);
|
|
3991
|
+
if (svg == null) {
|
|
3992
|
+
return null;
|
|
3993
|
+
}
|
|
3994
|
+
|
|
3995
|
+
svg.setDocumentWidth(width);
|
|
3996
|
+
svg.setDocumentHeight(height);
|
|
3997
|
+
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
|
3998
|
+
Canvas canvas = new Canvas(bitmap);
|
|
3999
|
+
svg.renderToCanvas(canvas);
|
|
4000
|
+
|
|
4001
|
+
Paint paint = new Paint();
|
|
4002
|
+
paint.setColorFilter(new PorterDuffColorFilter(iconColor, PorterDuff.Mode.SRC_IN));
|
|
4003
|
+
Canvas colorFilterCanvas = new Canvas(bitmap);
|
|
4004
|
+
colorFilterCanvas.drawBitmap(bitmap, 0, 0, paint);
|
|
4005
|
+
|
|
4006
|
+
BitmapDrawable drawable = new BitmapDrawable(_context.getResources(), bitmap);
|
|
4007
|
+
drawable.setBounds(0, 0, width, height);
|
|
4008
|
+
return drawable;
|
|
4009
|
+
} catch (IOException | SVGParseException e) {
|
|
4010
|
+
Log.e("InAppBrowser", "Error loading title asset icon: " + e.getMessage());
|
|
4011
|
+
} finally {
|
|
4012
|
+
if (inputStream != null) {
|
|
4013
|
+
try {
|
|
4014
|
+
inputStream.close();
|
|
4015
|
+
} catch (IOException e) {
|
|
4016
|
+
Log.e("InAppBrowser", "Error closing title icon stream: " + e.getMessage());
|
|
4017
|
+
}
|
|
4018
|
+
}
|
|
4019
|
+
}
|
|
4020
|
+
}
|
|
4021
|
+
|
|
4022
|
+
return null;
|
|
3866
4023
|
}
|
|
3867
4024
|
|
|
3868
4025
|
private void setupToolbar() {
|
|
@@ -3878,6 +4035,9 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
3878
4035
|
TextView titleText = _toolbar.findViewById(R.id.titleText);
|
|
3879
4036
|
|
|
3880
4037
|
// Determine icon and text color
|
|
4038
|
+
cachedTitleIconDrawable = null;
|
|
4039
|
+
cachedTitleIconResolved = false;
|
|
4040
|
+
|
|
3881
4041
|
int iconColor;
|
|
3882
4042
|
if (_options.getToolbarTextColor() != null && !_options.getToolbarTextColor().isEmpty()) {
|
|
3883
4043
|
try {
|
|
@@ -3938,30 +4098,21 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
3938
4098
|
_options.getCloseModalOk(),
|
|
3939
4099
|
new OnClickListener() {
|
|
3940
4100
|
public void onClick(DialogInterface dialog, int which) {
|
|
3941
|
-
// Close button clicked, do something
|
|
3942
|
-
dismiss();
|
|
3943
4101
|
if (_options != null && _options.getCallbacks() != null) {
|
|
3944
|
-
// Notify that confirm was clicked
|
|
3945
4102
|
_options.getCallbacks().confirmBtnClicked(currentUrl);
|
|
3946
|
-
_options.getCallbacks().closeEvent(currentUrl);
|
|
3947
4103
|
}
|
|
4104
|
+
performToolbarCloseAction(currentUrl);
|
|
3948
4105
|
}
|
|
3949
4106
|
}
|
|
3950
4107
|
)
|
|
3951
4108
|
.setNegativeButton(_options.getCloseModalCancel(), null)
|
|
3952
4109
|
.show();
|
|
3953
4110
|
} else {
|
|
3954
|
-
|
|
3955
|
-
if (_options != null && _options.getCallbacks() != null) {
|
|
3956
|
-
_options.getCallbacks().closeEvent(currentUrl);
|
|
3957
|
-
}
|
|
4111
|
+
performToolbarCloseAction(currentUrl);
|
|
3958
4112
|
}
|
|
3959
4113
|
} else {
|
|
3960
4114
|
String currentUrl = getUrl();
|
|
3961
|
-
|
|
3962
|
-
if (_options != null && _options.getCallbacks() != null) {
|
|
3963
|
-
_options.getCallbacks().closeEvent(currentUrl);
|
|
3964
|
-
}
|
|
4115
|
+
performToolbarCloseAction(currentUrl);
|
|
3965
4116
|
}
|
|
3966
4117
|
}
|
|
3967
4118
|
}
|