@capgo/capacitor-inappbrowser 8.16.5 → 8.17.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 +9 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/CapgoInAppBrowserPlugin.java +9 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/CloseButtonPositionSupport.java +35 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/Options.java +10 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/OrientationLayoutSupport.java +6 -2
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/SystemUiChromeSupport.java +11 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewBackNavigationSupport.java +3 -1
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java +123 -89
- package/dist/docs.json +36 -0
- package/dist/esm/definitions.d.ts +22 -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/CloseButtonPositionSupport.swift +15 -0
- package/ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift +12 -1
- package/ios/Sources/InAppBrowserPlugin/WKWebViewController.swift +76 -76
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1606,6 +1606,7 @@ See the README section "openSecureWindow (OAuth)" for full setup examples.
|
|
|
1606
1606
|
| **`isAnimated`** | <code>boolean</code> | Whether the webview opening is animated or not, ios only | <code>true</code> | |
|
|
1607
1607
|
| **`showReloadButton`** | <code>boolean</code> | Shows a reload button that reloads the web page | <code>false</code> | 1.0.15 |
|
|
1608
1608
|
| **`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 |
|
|
1609
|
+
| **`closeButtonPosition`** | <code><a href="#closebuttonposition">CloseButtonPosition</a></code> | Where the native toolbar close button is placed. When omitted, each platform keeps its convention: Android places the close button at the start, iOS at the end (or at the start when `showArrow` is true). Setting this option overrides that placement on both platforms. | | 8.17.0 |
|
|
1609
1610
|
| **`screenshotOnHide`** | <code>boolean</code> | Captures the visible webview and includes it as `screenshot` in `hideEvent` before the toolbar close button hides the webview. Only applies when `closeAction` is <a href="#closeaction">`CloseAction.HIDE`</a>. On iOS, capture uses `WKWebView.takeSnapshot`. When testing through Apple's iPhone Mirroring app with the physical device locked, the snapshot can succeed with the correct dimensions but a fully transparent PNG. Capture works as expected on a normal unlocked device. This appears to be an Apple mirroring limitation rather than a plugin bug. | <code>false</code> | 8.7.10 |
|
|
1610
1611
|
| **`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 |
|
|
1611
1612
|
| **`closeModalTitle`** | <code>string</code> | CloseModalTitle: title of the confirm when user clicks on close button | <code>"Close"</code> | 1.1.0 |
|
|
@@ -2015,6 +2016,14 @@ Native handling mode used after a managed download finishes.
|
|
|
2015
2016
|
| **`HIDE`** | <code>'hide'</code> | The toolbar close button hides the webview so it can be shown again. |
|
|
2016
2017
|
|
|
2017
2018
|
|
|
2019
|
+
#### CloseButtonPosition
|
|
2020
|
+
|
|
2021
|
+
| Members | Value | Description |
|
|
2022
|
+
| ----------- | -------------------- | -------------------------------------------------------------- |
|
|
2023
|
+
| **`START`** | <code>'start'</code> | Leading edge of the toolbar (left in left-to-right layouts). |
|
|
2024
|
+
| **`END`** | <code>'end'</code> | Trailing edge of the toolbar (right in left-to-right layouts). |
|
|
2025
|
+
|
|
2026
|
+
|
|
2018
2027
|
#### InvisibilityMode
|
|
2019
2028
|
|
|
2020
2029
|
| Members | Value | Description |
|
|
@@ -1072,6 +1072,15 @@ public class CapgoInAppBrowserPlugin extends Plugin implements WebViewDialog.Per
|
|
|
1072
1072
|
return;
|
|
1073
1073
|
}
|
|
1074
1074
|
options.setCloseAction(closeAction);
|
|
1075
|
+
String closeButtonPosition = call.getString("closeButtonPosition");
|
|
1076
|
+
if (closeButtonPosition != null) {
|
|
1077
|
+
closeButtonPosition = closeButtonPosition.toLowerCase(Locale.ROOT);
|
|
1078
|
+
if (CloseButtonPositionSupport.gravityFor(closeButtonPosition) == null) {
|
|
1079
|
+
call.reject("closeButtonPosition must be 'start' or 'end'");
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
options.setCloseButtonPosition(closeButtonPosition);
|
|
1075
1084
|
options.setTitleFontFamily(call.getString("titleFontFamily"));
|
|
1076
1085
|
JSObject titleIconObj = call.getObject("titleIcon");
|
|
1077
1086
|
if (titleIconObj != null) {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
package ee.forgr.capacitor_inappbrowser;
|
|
2
|
+
|
|
3
|
+
import android.view.Gravity;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Maps the {@code closeButtonPosition} option onto toolbar layout values.
|
|
7
|
+
*/
|
|
8
|
+
final class CloseButtonPositionSupport {
|
|
9
|
+
|
|
10
|
+
/** End padding that visually matches the start side's toolbar content inset. */
|
|
11
|
+
static final int END_PADDING_DP = 20;
|
|
12
|
+
|
|
13
|
+
private CloseButtonPositionSupport() {}
|
|
14
|
+
|
|
15
|
+
/** Toolbar gravity for the option value, or {@code null} to keep the layout default. */
|
|
16
|
+
static Integer gravityFor(String closeButtonPosition) {
|
|
17
|
+
if ("start".equals(closeButtonPosition)) {
|
|
18
|
+
return Gravity.START;
|
|
19
|
+
}
|
|
20
|
+
if ("end".equals(closeButtonPosition)) {
|
|
21
|
+
return Gravity.END;
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Keeps the layout's edge nudge pointing outwards for the resolved gravity.
|
|
28
|
+
* Resolves start/end against the layout direction so RTL mirrors correctly.
|
|
29
|
+
*/
|
|
30
|
+
static float mirroredTranslationX(int gravity, int layoutDirection, float translationX) {
|
|
31
|
+
int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
|
|
32
|
+
float outwards = Math.abs(translationX);
|
|
33
|
+
return absoluteGravity == Gravity.RIGHT ? outwards : -outwards;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -146,6 +146,7 @@ public class Options {
|
|
|
146
146
|
private String CloseModalCancel;
|
|
147
147
|
private ButtonNearDone buttonNearDone;
|
|
148
148
|
private String closeAction = "close";
|
|
149
|
+
private String closeButtonPosition;
|
|
149
150
|
private String titleFontFamily;
|
|
150
151
|
private ButtonNearDone titleIcon;
|
|
151
152
|
private String CloseModalOk;
|
|
@@ -466,6 +467,14 @@ public class Options {
|
|
|
466
467
|
this.closeAction = closeAction;
|
|
467
468
|
}
|
|
468
469
|
|
|
470
|
+
public String getCloseButtonPosition() {
|
|
471
|
+
return closeButtonPosition;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
public void setCloseButtonPosition(String closeButtonPosition) {
|
|
475
|
+
this.closeButtonPosition = closeButtonPosition;
|
|
476
|
+
}
|
|
477
|
+
|
|
469
478
|
public String getTitleFontFamily() {
|
|
470
479
|
return titleFontFamily;
|
|
471
480
|
}
|
|
@@ -834,6 +843,7 @@ public class Options {
|
|
|
834
843
|
copy.setCloseModalURLPattern(closeModalURLPattern);
|
|
835
844
|
copy.setButtonNearDone(buttonNearDone);
|
|
836
845
|
copy.setCloseAction(closeAction);
|
|
846
|
+
copy.setCloseButtonPosition(closeButtonPosition);
|
|
837
847
|
copy.setTitleFontFamily(titleFontFamily);
|
|
838
848
|
copy.setTitleIcon(titleIcon);
|
|
839
849
|
copy.setUrl("about:blank");
|
|
@@ -16,11 +16,13 @@ final class OrientationLayoutSupport {
|
|
|
16
16
|
Integer previousScreenHeightDp,
|
|
17
17
|
Integer previousSmallestScreenWidthDp,
|
|
18
18
|
Integer previousDensityDpi,
|
|
19
|
+
Integer previousUiMode,
|
|
19
20
|
int currentOrientation,
|
|
20
21
|
int currentScreenWidthDp,
|
|
21
22
|
int currentScreenHeightDp,
|
|
22
23
|
int currentSmallestScreenWidthDp,
|
|
23
|
-
int currentDensityDpi
|
|
24
|
+
int currentDensityDpi,
|
|
25
|
+
int currentUiMode
|
|
24
26
|
) {
|
|
25
27
|
if (previousOrientation == null) {
|
|
26
28
|
return true;
|
|
@@ -35,7 +37,9 @@ final class OrientationLayoutSupport {
|
|
|
35
37
|
previousSmallestScreenWidthDp == null ||
|
|
36
38
|
previousSmallestScreenWidthDp != currentSmallestScreenWidthDp ||
|
|
37
39
|
previousDensityDpi == null ||
|
|
38
|
-
previousDensityDpi != currentDensityDpi
|
|
40
|
+
previousDensityDpi != currentDensityDpi ||
|
|
41
|
+
previousUiMode == null ||
|
|
42
|
+
previousUiMode != currentUiMode
|
|
39
43
|
);
|
|
40
44
|
}
|
|
41
45
|
}
|
|
@@ -34,6 +34,17 @@ final class SystemUiChromeSupport {
|
|
|
34
34
|
return !edgeToEdge && shouldUsePreApi30LayoutFlags(sdkInt);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Color painted behind the browser content, visible in the system bar insets. Follows the toolbar
|
|
39
|
+
* color when one is set, otherwise the system theme, so the dialog theme's default never shows.
|
|
40
|
+
*/
|
|
41
|
+
static int resolveWindowBackgroundColor(Integer toolbarColor, boolean darkTheme) {
|
|
42
|
+
if (toolbarColor != null) {
|
|
43
|
+
return toolbarColor;
|
|
44
|
+
}
|
|
45
|
+
return darkTheme ? Color.BLACK : Color.WHITE;
|
|
46
|
+
}
|
|
47
|
+
|
|
37
48
|
static void setDecorFitsSystemWindows(Window window, boolean decorFitsSystemWindows) {
|
|
38
49
|
if (window == null) {
|
|
39
50
|
return;
|
package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewBackNavigationSupport.java
CHANGED
|
@@ -25,7 +25,9 @@ final class WebViewBackNavigationSupport {
|
|
|
25
25
|
/**
|
|
26
26
|
* When {@code disableGoBackOnNativeApplication} is true, the dialog must not be cancelable on
|
|
27
27
|
* back/gesture. Otherwise {@link androidx.activity.ComponentDialog}'s built-in back callback
|
|
28
|
-
* dismisses the dialog before our handler can return {@link Action#IGNORE}.
|
|
28
|
+
* dismisses the dialog before our handler can return {@link Action#IGNORE}. While cancelable is
|
|
29
|
+
* false that built-in callback still consumes back without dismissing, so {@link WebViewDialog}
|
|
30
|
+
* must keep its own callback registered last on the dispatcher.
|
|
29
31
|
*/
|
|
30
32
|
static boolean isCancelableOnBack(boolean disableGoBackOnNativeApplication) {
|
|
31
33
|
return !disableGoBackOnNativeApplication;
|
|
@@ -469,7 +469,9 @@ public class WebViewDialog extends ComponentDialog implements ProxyResponseRouti
|
|
|
469
469
|
@Override
|
|
470
470
|
protected void onStart() {
|
|
471
471
|
super.onStart();
|
|
472
|
-
|
|
472
|
+
// ComponentDialog registers its own back callback in onCreate; re-add ours last so
|
|
473
|
+
// handleBrowserBackNavigation runs before the built-in cancel callback (LIFO order).
|
|
474
|
+
ensureDialogBackHandlerOnTop();
|
|
473
475
|
}
|
|
474
476
|
|
|
475
477
|
@Override
|
|
@@ -2212,9 +2214,9 @@ public class WebViewDialog extends ComponentDialog implements ProxyResponseRouti
|
|
|
2212
2214
|
boolean isDarkBackground = isDarkColor(toolbarColor);
|
|
2213
2215
|
insetsController.setAppearanceLightStatusBars(!isDarkBackground);
|
|
2214
2216
|
} catch (IllegalArgumentException e) {
|
|
2215
|
-
|
|
2216
|
-
statusBarColorView.setBackgroundColor(
|
|
2217
|
-
insetsController.setAppearanceLightStatusBars(
|
|
2217
|
+
int fallbackColor = resolveWindowBackgroundColor();
|
|
2218
|
+
statusBarColorView.setBackgroundColor(fallbackColor);
|
|
2219
|
+
insetsController.setAppearanceLightStatusBars(!isDarkThemeEnabled());
|
|
2218
2220
|
}
|
|
2219
2221
|
} else {
|
|
2220
2222
|
// Follow system dark mode if no toolbar color provided
|
|
@@ -2921,6 +2923,19 @@ public class WebViewDialog extends ComponentDialog implements ProxyResponseRouti
|
|
|
2921
2923
|
if (dialogBackCallback != null) {
|
|
2922
2924
|
return;
|
|
2923
2925
|
}
|
|
2926
|
+
ensureDialogBackHandlerOnTop();
|
|
2927
|
+
}
|
|
2928
|
+
|
|
2929
|
+
/**
|
|
2930
|
+
* Re-register the dialog back callback so it sits above {@link ComponentDialog}'s built-in
|
|
2931
|
+
* callback. That callback is always enabled and consumes back without dismissing when
|
|
2932
|
+
* {@link #setCancelable(boolean)} is false, which would block webview history navigation.
|
|
2933
|
+
*/
|
|
2934
|
+
private void ensureDialogBackHandlerOnTop() {
|
|
2935
|
+
if (dialogBackCallback != null) {
|
|
2936
|
+
dialogBackCallback.remove();
|
|
2937
|
+
dialogBackCallback = null;
|
|
2938
|
+
}
|
|
2924
2939
|
// Predictive back (API 33+) never delivers KEYCODE_BACK to Dialog OnKeyListener.
|
|
2925
2940
|
dialogBackCallback = new OnBackPressedCallback(false) {
|
|
2926
2941
|
@Override
|
|
@@ -2949,7 +2964,11 @@ public class WebViewDialog extends ComponentDialog implements ProxyResponseRouti
|
|
|
2949
2964
|
void applyBackNavigationPolicy() {
|
|
2950
2965
|
boolean disableGoBack = _options != null && _options.getDisableGoBackOnNativeApplication();
|
|
2951
2966
|
setCancelable(WebViewBackNavigationSupport.isCancelableOnBack(disableGoBack));
|
|
2952
|
-
|
|
2967
|
+
if (isShowing()) {
|
|
2968
|
+
ensureDialogBackHandlerOnTop();
|
|
2969
|
+
} else {
|
|
2970
|
+
syncBackNavigationHandlers();
|
|
2971
|
+
}
|
|
2953
2972
|
}
|
|
2954
2973
|
|
|
2955
2974
|
private void syncBackNavigationHandlers() {
|
|
@@ -3431,6 +3450,7 @@ public class WebViewDialog extends ComponentDialog implements ProxyResponseRouti
|
|
|
3431
3450
|
Integer previousScreenHeightDp = lastConfiguration != null ? lastConfiguration.screenHeightDp : null;
|
|
3432
3451
|
Integer previousSmallestScreenWidthDp = lastConfiguration != null ? lastConfiguration.smallestScreenWidthDp : null;
|
|
3433
3452
|
Integer previousDensityDpi = lastConfiguration != null ? lastConfiguration.densityDpi : null;
|
|
3453
|
+
Integer previousUiMode = lastConfiguration != null ? lastConfiguration.uiMode : null;
|
|
3434
3454
|
|
|
3435
3455
|
int currentOrientation = newConfig != null ? newConfig.orientation : (previousOrientation != null ? previousOrientation : 0);
|
|
3436
3456
|
int currentScreenWidthDp =
|
|
@@ -3442,6 +3462,7 @@ public class WebViewDialog extends ComponentDialog implements ProxyResponseRouti
|
|
|
3442
3462
|
? newConfig.smallestScreenWidthDp
|
|
3443
3463
|
: (previousSmallestScreenWidthDp != null ? previousSmallestScreenWidthDp : 0);
|
|
3444
3464
|
int currentDensityDpi = newConfig != null ? newConfig.densityDpi : (previousDensityDpi != null ? previousDensityDpi : 0);
|
|
3465
|
+
int currentUiMode = newConfig != null ? newConfig.uiMode : (previousUiMode != null ? previousUiMode : 0);
|
|
3445
3466
|
|
|
3446
3467
|
boolean shouldRefresh = OrientationLayoutSupport.shouldRefreshBrowserLayout(
|
|
3447
3468
|
previousOrientation,
|
|
@@ -3449,11 +3470,13 @@ public class WebViewDialog extends ComponentDialog implements ProxyResponseRouti
|
|
|
3449
3470
|
previousScreenHeightDp,
|
|
3450
3471
|
previousSmallestScreenWidthDp,
|
|
3451
3472
|
previousDensityDpi,
|
|
3473
|
+
previousUiMode,
|
|
3452
3474
|
currentOrientation,
|
|
3453
3475
|
currentScreenWidthDp,
|
|
3454
3476
|
currentScreenHeightDp,
|
|
3455
3477
|
currentSmallestScreenWidthDp,
|
|
3456
|
-
currentDensityDpi
|
|
3478
|
+
currentDensityDpi,
|
|
3479
|
+
currentUiMode
|
|
3457
3480
|
);
|
|
3458
3481
|
|
|
3459
3482
|
if (newConfig != null) {
|
|
@@ -3494,6 +3517,7 @@ public class WebViewDialog extends ComponentDialog implements ProxyResponseRouti
|
|
|
3494
3517
|
}
|
|
3495
3518
|
|
|
3496
3519
|
ensureContentBrowserMatchParentHeight();
|
|
3520
|
+
applyWindowBackgroundColor();
|
|
3497
3521
|
|
|
3498
3522
|
boolean isBlankToolbar = _options != null && TextUtils.equals(_options.getToolbarType(), "blank");
|
|
3499
3523
|
if (isBlankToolbar) {
|
|
@@ -3580,18 +3604,7 @@ public class WebViewDialog extends ComponentDialog implements ProxyResponseRouti
|
|
|
3580
3604
|
appBarLayout.setStateListAnimator(null);
|
|
3581
3605
|
appBarLayout.setOutlineProvider(null);
|
|
3582
3606
|
|
|
3583
|
-
int
|
|
3584
|
-
if (_options.getToolbarColor() != null && !_options.getToolbarColor().isEmpty()) {
|
|
3585
|
-
try {
|
|
3586
|
-
backgroundColor = Color.parseColor(_options.getToolbarColor());
|
|
3587
|
-
} catch (IllegalArgumentException e) {
|
|
3588
|
-
Log.e("InAppBrowser", "Invalid toolbar color, using black: " + e.getMessage());
|
|
3589
|
-
}
|
|
3590
|
-
} else {
|
|
3591
|
-
backgroundColor = isDarkThemeEnabled() ? Color.BLACK : Color.WHITE;
|
|
3592
|
-
}
|
|
3593
|
-
|
|
3594
|
-
final int finalBgColor = backgroundColor;
|
|
3607
|
+
final int finalBgColor = resolveWindowBackgroundColor();
|
|
3595
3608
|
_webView.post(() -> {
|
|
3596
3609
|
if (_webView == null) {
|
|
3597
3610
|
return;
|
|
@@ -3611,6 +3624,12 @@ public class WebViewDialog extends ComponentDialog implements ProxyResponseRouti
|
|
|
3611
3624
|
|
|
3612
3625
|
applyAppBarTopInset(appBarLayout, appBarHandlesTopInset(toolbarView) ? statusBarHeight : 0);
|
|
3613
3626
|
appBarLayout.setBackgroundColor(finalBgColor);
|
|
3627
|
+
|
|
3628
|
+
Window window = getWindow();
|
|
3629
|
+
if (window != null) {
|
|
3630
|
+
WindowInsetsControllerCompat insetsController = new WindowInsetsControllerCompat(window, window.getDecorView());
|
|
3631
|
+
insetsController.setAppearanceLightStatusBars(!isDarkColor(finalBgColor));
|
|
3632
|
+
}
|
|
3614
3633
|
});
|
|
3615
3634
|
}
|
|
3616
3635
|
|
|
@@ -3855,6 +3874,29 @@ public class WebViewDialog extends ComponentDialog implements ProxyResponseRouti
|
|
|
3855
3874
|
}
|
|
3856
3875
|
}
|
|
3857
3876
|
|
|
3877
|
+
private int resolveWindowBackgroundColor() {
|
|
3878
|
+
Integer toolbarColor = null;
|
|
3879
|
+
if (_options.getToolbarColor() != null && !_options.getToolbarColor().isEmpty()) {
|
|
3880
|
+
try {
|
|
3881
|
+
toolbarColor = Color.parseColor(_options.getToolbarColor());
|
|
3882
|
+
} catch (IllegalArgumentException e) {
|
|
3883
|
+
Log.e("InAppBrowser", "Invalid toolbar color, using theme default: " + e.getMessage());
|
|
3884
|
+
}
|
|
3885
|
+
}
|
|
3886
|
+
return SystemUiChromeSupport.resolveWindowBackgroundColor(toolbarColor, isDarkThemeEnabled());
|
|
3887
|
+
}
|
|
3888
|
+
|
|
3889
|
+
private void applyWindowBackgroundColor() {
|
|
3890
|
+
// Custom dimensions keep the window transparent for touch passthrough
|
|
3891
|
+
if (_options.getWidth() != null || _options.getHeight() != null) {
|
|
3892
|
+
return;
|
|
3893
|
+
}
|
|
3894
|
+
Window window = getWindow();
|
|
3895
|
+
if (window != null) {
|
|
3896
|
+
window.getDecorView().setBackgroundColor(resolveWindowBackgroundColor());
|
|
3897
|
+
}
|
|
3898
|
+
}
|
|
3899
|
+
|
|
3858
3900
|
private int getSystemStatusBarHeight() {
|
|
3859
3901
|
int resourceId = getContext().getResources().getIdentifier("status_bar_height", "dimen", "android");
|
|
3860
3902
|
if (resourceId <= 0) {
|
|
@@ -4932,62 +4974,85 @@ public class WebViewDialog extends ComponentDialog implements ProxyResponseRouti
|
|
|
4932
4974
|
|
|
4933
4975
|
private void setupToolbar() {
|
|
4934
4976
|
_toolbar = findViewById(R.id.tool_bar);
|
|
4977
|
+
applyWindowBackgroundColor();
|
|
4935
4978
|
|
|
4936
4979
|
// Apply toolbar color early, for ALL toolbar types, before any view configuration
|
|
4937
4980
|
if (_options.getToolbarColor() != null && !_options.getToolbarColor().isEmpty()) {
|
|
4981
|
+
int toolbarColor;
|
|
4938
4982
|
try {
|
|
4939
|
-
|
|
4940
|
-
|
|
4983
|
+
toolbarColor = Color.parseColor(_options.getToolbarColor());
|
|
4984
|
+
} catch (IllegalArgumentException e) {
|
|
4985
|
+
Log.e("InAppBrowser", "Invalid toolbar color, using theme default: " + e.getMessage());
|
|
4986
|
+
toolbarColor = resolveWindowBackgroundColor();
|
|
4987
|
+
}
|
|
4941
4988
|
|
|
4942
|
-
|
|
4943
|
-
TextView titleText = _toolbar.findViewById(R.id.titleText);
|
|
4989
|
+
_toolbar.setBackgroundColor(toolbarColor);
|
|
4944
4990
|
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
cachedTitleIconResolved = false;
|
|
4991
|
+
// Get toolbar title and ensure it gets the right color
|
|
4992
|
+
TextView titleText = _toolbar.findViewById(R.id.titleText);
|
|
4948
4993
|
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
// No explicit toolbarTextColor, use automatic detection based on background
|
|
4994
|
+
// Determine icon and text color
|
|
4995
|
+
cachedTitleIconDrawable = null;
|
|
4996
|
+
cachedTitleIconResolved = false;
|
|
4997
|
+
|
|
4998
|
+
int iconColor;
|
|
4999
|
+
if (_options.getToolbarTextColor() != null && !_options.getToolbarTextColor().isEmpty()) {
|
|
5000
|
+
try {
|
|
5001
|
+
iconColor = Color.parseColor(_options.getToolbarTextColor());
|
|
5002
|
+
} catch (IllegalArgumentException e) {
|
|
5003
|
+
// Fallback to automatic detection if parsing fails
|
|
4960
5004
|
boolean isDarkBackground = isDarkColor(toolbarColor);
|
|
4961
5005
|
iconColor = isDarkBackground ? Color.WHITE : Color.BLACK;
|
|
4962
5006
|
}
|
|
5007
|
+
} else {
|
|
5008
|
+
// No explicit toolbarTextColor, use automatic detection based on background
|
|
5009
|
+
boolean isDarkBackground = isDarkColor(toolbarColor);
|
|
5010
|
+
iconColor = isDarkBackground ? Color.WHITE : Color.BLACK;
|
|
5011
|
+
}
|
|
4963
5012
|
|
|
4964
|
-
|
|
4965
|
-
|
|
5013
|
+
// Store for later use with navigation buttons
|
|
5014
|
+
this.iconColor = iconColor;
|
|
4966
5015
|
|
|
4967
|
-
|
|
4968
|
-
|
|
5016
|
+
// Set title text color directly
|
|
5017
|
+
titleText.setTextColor(iconColor);
|
|
4969
5018
|
|
|
4970
|
-
|
|
4971
|
-
|
|
5019
|
+
// Apply colors to all buttons
|
|
5020
|
+
applyColorToAllButtons(toolbarColor, iconColor);
|
|
4972
5021
|
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
5022
|
+
// Also ensure status bar gets the color
|
|
5023
|
+
if (getWindow() != null) {
|
|
5024
|
+
SystemUiChromeSupport.applyLegacyStatusBarColorViaView(findViewById(R.id.status_bar_color_view), toolbarColor);
|
|
4976
5025
|
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
getWindow().getDecorView()
|
|
4982
|
-
);
|
|
4983
|
-
insetsController.setAppearanceLightStatusBars(!isDarkBackground);
|
|
4984
|
-
}
|
|
4985
|
-
} catch (IllegalArgumentException e) {
|
|
4986
|
-
Log.e("InAppBrowser", "Invalid toolbar color: " + _options.getToolbarColor());
|
|
5026
|
+
// Determine proper status bar text color (light or dark icons)
|
|
5027
|
+
boolean isDarkBackground = isDarkColor(toolbarColor);
|
|
5028
|
+
WindowInsetsControllerCompat insetsController = new WindowInsetsControllerCompat(getWindow(), getWindow().getDecorView());
|
|
5029
|
+
insetsController.setAppearanceLightStatusBars(!isDarkBackground);
|
|
4987
5030
|
}
|
|
4988
5031
|
}
|
|
4989
5032
|
|
|
4990
5033
|
ImageButton closeButtonView = _toolbar.findViewById(R.id.closeButton);
|
|
5034
|
+
Integer closeButtonGravity = CloseButtonPositionSupport.gravityFor(_options.getCloseButtonPosition());
|
|
5035
|
+
if (closeButtonGravity != null && closeButtonView.getLayoutParams() instanceof Toolbar.LayoutParams closeButtonParams) {
|
|
5036
|
+
int verticalGravity = closeButtonParams.gravity & Gravity.VERTICAL_GRAVITY_MASK;
|
|
5037
|
+
closeButtonParams.gravity = verticalGravity | closeButtonGravity;
|
|
5038
|
+
closeButtonView.setLayoutParams(closeButtonParams);
|
|
5039
|
+
closeButtonView.setTranslationX(
|
|
5040
|
+
CloseButtonPositionSupport.mirroredTranslationX(
|
|
5041
|
+
closeButtonGravity,
|
|
5042
|
+
_context.getResources().getConfiguration().getLayoutDirection(),
|
|
5043
|
+
closeButtonView.getTranslationX()
|
|
5044
|
+
)
|
|
5045
|
+
);
|
|
5046
|
+
// Toolbar only insets the start edge; pad the logical end so the icon keeps clear of the screen edge
|
|
5047
|
+
if (closeButtonGravity == Gravity.END) {
|
|
5048
|
+
closeButtonView.setPaddingRelative(
|
|
5049
|
+
closeButtonView.getPaddingStart(),
|
|
5050
|
+
closeButtonView.getPaddingTop(),
|
|
5051
|
+
(int) getPixels(CloseButtonPositionSupport.END_PADDING_DP),
|
|
5052
|
+
closeButtonView.getPaddingBottom()
|
|
5053
|
+
);
|
|
5054
|
+
}
|
|
5055
|
+
}
|
|
4991
5056
|
closeButtonView.setOnClickListener(
|
|
4992
5057
|
new View.OnClickListener() {
|
|
4993
5058
|
@Override
|
|
@@ -5091,41 +5156,10 @@ public class WebViewDialog extends ComponentDialog implements ProxyResponseRouti
|
|
|
5091
5156
|
configureBlankToolbarLayout();
|
|
5092
5157
|
requestSafeAreaInsets();
|
|
5093
5158
|
|
|
5094
|
-
//
|
|
5159
|
+
// Without a toolbar the status bar view is the only chrome, so it follows the window color
|
|
5095
5160
|
View statusBarColorView = findViewById(R.id.status_bar_color_view);
|
|
5096
|
-
if (
|
|
5097
|
-
|
|
5098
|
-
int toolbarColor = Color.parseColor(_options.getToolbarColor());
|
|
5099
|
-
if (getWindow() != null) {
|
|
5100
|
-
getWindow().getDecorView().setBackgroundColor(toolbarColor);
|
|
5101
|
-
}
|
|
5102
|
-
// Also set status bar color view background if available
|
|
5103
|
-
if (statusBarColorView != null) {
|
|
5104
|
-
statusBarColorView.setBackgroundColor(toolbarColor);
|
|
5105
|
-
}
|
|
5106
|
-
} catch (IllegalArgumentException e) {
|
|
5107
|
-
// Fallback to system default if color parsing fails
|
|
5108
|
-
boolean isDarkTheme = isDarkThemeEnabled();
|
|
5109
|
-
int windowBackgroundColor = isDarkTheme ? Color.BLACK : Color.WHITE;
|
|
5110
|
-
if (getWindow() != null) {
|
|
5111
|
-
getWindow().getDecorView().setBackgroundColor(windowBackgroundColor);
|
|
5112
|
-
}
|
|
5113
|
-
// Also set status bar color view background if available
|
|
5114
|
-
if (statusBarColorView != null) {
|
|
5115
|
-
statusBarColorView.setBackgroundColor(windowBackgroundColor);
|
|
5116
|
-
}
|
|
5117
|
-
}
|
|
5118
|
-
} else {
|
|
5119
|
-
// Follow system dark mode
|
|
5120
|
-
boolean isDarkTheme = isDarkThemeEnabled();
|
|
5121
|
-
int windowBackgroundColor = isDarkTheme ? Color.BLACK : Color.WHITE;
|
|
5122
|
-
if (getWindow() != null) {
|
|
5123
|
-
getWindow().getDecorView().setBackgroundColor(windowBackgroundColor);
|
|
5124
|
-
}
|
|
5125
|
-
// Also set status bar color view background if available
|
|
5126
|
-
if (statusBarColorView != null) {
|
|
5127
|
-
statusBarColorView.setBackgroundColor(windowBackgroundColor);
|
|
5128
|
-
}
|
|
5161
|
+
if (statusBarColorView != null) {
|
|
5162
|
+
statusBarColorView.setBackgroundColor(resolveWindowBackgroundColor());
|
|
5129
5163
|
}
|
|
5130
5164
|
} else {
|
|
5131
5165
|
_toolbar.findViewById(R.id.forwardButton).setVisibility(View.GONE);
|
package/dist/docs.json
CHANGED
|
@@ -1954,6 +1954,24 @@
|
|
|
1954
1954
|
],
|
|
1955
1955
|
"type": "CloseAction"
|
|
1956
1956
|
},
|
|
1957
|
+
{
|
|
1958
|
+
"name": "closeButtonPosition",
|
|
1959
|
+
"tags": [
|
|
1960
|
+
{
|
|
1961
|
+
"text": "8.17.0",
|
|
1962
|
+
"name": "since"
|
|
1963
|
+
},
|
|
1964
|
+
{
|
|
1965
|
+
"text": "closeButtonPosition: CloseButtonPosition.END",
|
|
1966
|
+
"name": "example"
|
|
1967
|
+
}
|
|
1968
|
+
],
|
|
1969
|
+
"docs": "Where the native toolbar close button is placed.\n\nWhen omitted, each platform keeps its convention: Android places the close button at the\nstart, iOS at the end (or at the start when `showArrow` is true). Setting this option\noverrides that placement on both platforms.",
|
|
1970
|
+
"complexTypes": [
|
|
1971
|
+
"CloseButtonPosition"
|
|
1972
|
+
],
|
|
1973
|
+
"type": "CloseButtonPosition"
|
|
1974
|
+
},
|
|
1957
1975
|
{
|
|
1958
1976
|
"name": "screenshotOnHide",
|
|
1959
1977
|
"tags": [
|
|
@@ -3654,6 +3672,24 @@
|
|
|
3654
3672
|
}
|
|
3655
3673
|
]
|
|
3656
3674
|
},
|
|
3675
|
+
{
|
|
3676
|
+
"name": "CloseButtonPosition",
|
|
3677
|
+
"slug": "closebuttonposition",
|
|
3678
|
+
"members": [
|
|
3679
|
+
{
|
|
3680
|
+
"name": "START",
|
|
3681
|
+
"value": "'start'",
|
|
3682
|
+
"tags": [],
|
|
3683
|
+
"docs": "Leading edge of the toolbar (left in left-to-right layouts)."
|
|
3684
|
+
},
|
|
3685
|
+
{
|
|
3686
|
+
"name": "END",
|
|
3687
|
+
"value": "'end'",
|
|
3688
|
+
"tags": [],
|
|
3689
|
+
"docs": "Trailing edge of the toolbar (right in left-to-right layouts)."
|
|
3690
|
+
}
|
|
3691
|
+
]
|
|
3692
|
+
},
|
|
3657
3693
|
{
|
|
3658
3694
|
"name": "InvisibilityMode",
|
|
3659
3695
|
"slug": "invisibilitymode",
|
|
@@ -105,6 +105,16 @@ export declare enum CloseAction {
|
|
|
105
105
|
*/
|
|
106
106
|
HIDE = "hide"
|
|
107
107
|
}
|
|
108
|
+
export declare enum CloseButtonPosition {
|
|
109
|
+
/**
|
|
110
|
+
* Leading edge of the toolbar (left in left-to-right layouts).
|
|
111
|
+
*/
|
|
112
|
+
START = "start",
|
|
113
|
+
/**
|
|
114
|
+
* Trailing edge of the toolbar (right in left-to-right layouts).
|
|
115
|
+
*/
|
|
116
|
+
END = "end"
|
|
117
|
+
}
|
|
108
118
|
export interface ToolbarTitleIconOptions {
|
|
109
119
|
ios?: {
|
|
110
120
|
iconType: 'sf-symbol' | 'asset';
|
|
@@ -975,6 +985,18 @@ export interface OpenWebViewOptions {
|
|
|
975
985
|
* closeAction: CloseAction.HIDE
|
|
976
986
|
*/
|
|
977
987
|
closeAction?: CloseAction;
|
|
988
|
+
/**
|
|
989
|
+
* Where the native toolbar close button is placed.
|
|
990
|
+
*
|
|
991
|
+
* When omitted, each platform keeps its convention: Android places the close button at the
|
|
992
|
+
* start, iOS at the end (or at the start when `showArrow` is true). Setting this option
|
|
993
|
+
* overrides that placement on both platforms.
|
|
994
|
+
*
|
|
995
|
+
* @since 8.17.0
|
|
996
|
+
* @example
|
|
997
|
+
* closeButtonPosition: CloseButtonPosition.END
|
|
998
|
+
*/
|
|
999
|
+
closeButtonPosition?: CloseButtonPosition;
|
|
978
1000
|
/**
|
|
979
1001
|
* Captures the visible webview and includes it as `screenshot` in `hideEvent`
|
|
980
1002
|
* before the toolbar close button hides the webview.
|
package/dist/esm/definitions.js
CHANGED
|
@@ -48,4 +48,15 @@ export var CloseAction;
|
|
|
48
48
|
*/
|
|
49
49
|
CloseAction["HIDE"] = "hide";
|
|
50
50
|
})(CloseAction || (CloseAction = {}));
|
|
51
|
+
export var CloseButtonPosition;
|
|
52
|
+
(function (CloseButtonPosition) {
|
|
53
|
+
/**
|
|
54
|
+
* Leading edge of the toolbar (left in left-to-right layouts).
|
|
55
|
+
*/
|
|
56
|
+
CloseButtonPosition["START"] = "start";
|
|
57
|
+
/**
|
|
58
|
+
* Trailing edge of the toolbar (right in left-to-right layouts).
|
|
59
|
+
*/
|
|
60
|
+
CloseButtonPosition["END"] = "end";
|
|
61
|
+
})(CloseButtonPosition || (CloseButtonPosition = {}));
|
|
51
62
|
//# sourceMappingURL=definitions.js.map
|