@capgo/inappbrowser 7.3.2 → 7.4.1
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 +48 -42
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/InAppBrowserPlugin.java +149 -41
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/Options.java +65 -22
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewCallbacks.java +2 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java +647 -92
- package/android/src/main/res/drawable/ic_share.xml +10 -0
- package/android/src/main/res/layout/activity_browser.xml +8 -0
- package/android/src/main/res/layout/tool_bar.xml +19 -7
- package/android/src/main/res/values/strings.xml +2 -0
- package/dist/docs.json +171 -37
- package/dist/esm/definitions.d.ts +224 -31
- package/dist/esm/definitions.js +12 -1
- package/dist/esm/definitions.js.map +1 -1
- package/dist/plugin.cjs.js +12 -1
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +12 -1
- package/dist/plugin.js.map +1 -1
- package/ios/Plugin/InAppBrowserPlugin.swift +339 -44
- package/ios/Plugin/WKWebViewController.swift +478 -45
- package/package.json +1 -1
- package/ios/Plugin/Assets.xcassets/Back.imageset/Back.png +0 -0
- package/ios/Plugin/Assets.xcassets/Back.imageset/Back@2x.png +0 -0
- package/ios/Plugin/Assets.xcassets/Back.imageset/Back@3x.png +0 -0
- package/ios/Plugin/Assets.xcassets/Back.imageset/Contents.json +0 -26
- package/ios/Plugin/Assets.xcassets/Contents.json +0 -6
- package/ios/Plugin/Assets.xcassets/Forward.imageset/Contents.json +0 -26
- package/ios/Plugin/Assets.xcassets/Forward.imageset/Forward.png +0 -0
- package/ios/Plugin/Assets.xcassets/Forward.imageset/Forward@2x.png +0 -0
- package/ios/Plugin/Assets.xcassets/Forward.imageset/Forward@3x.png +0 -0
|
@@ -9,15 +9,21 @@ import android.content.Context;
|
|
|
9
9
|
import android.content.DialogInterface;
|
|
10
10
|
import android.content.Intent;
|
|
11
11
|
import android.content.res.AssetManager;
|
|
12
|
+
import android.content.res.Resources;
|
|
12
13
|
import android.graphics.Bitmap;
|
|
14
|
+
import android.graphics.Canvas;
|
|
13
15
|
import android.graphics.Color;
|
|
16
|
+
import android.graphics.Paint;
|
|
14
17
|
import android.graphics.Picture;
|
|
18
|
+
import android.graphics.PorterDuff;
|
|
19
|
+
import android.graphics.PorterDuffColorFilter;
|
|
15
20
|
import android.graphics.drawable.PictureDrawable;
|
|
16
21
|
import android.net.Uri;
|
|
17
22
|
import android.net.http.SslError;
|
|
18
23
|
import android.text.TextUtils;
|
|
19
24
|
import android.util.Base64;
|
|
20
25
|
import android.util.Log;
|
|
26
|
+
import android.util.TypedValue;
|
|
21
27
|
import android.view.View;
|
|
22
28
|
import android.view.Window;
|
|
23
29
|
import android.view.WindowManager;
|
|
@@ -33,6 +39,7 @@ import android.webkit.WebResourceResponse;
|
|
|
33
39
|
import android.webkit.WebView;
|
|
34
40
|
import android.webkit.WebViewClient;
|
|
35
41
|
import android.widget.ImageButton;
|
|
42
|
+
import android.widget.ImageView;
|
|
36
43
|
import android.widget.TextView;
|
|
37
44
|
import android.widget.Toast;
|
|
38
45
|
import android.widget.Toolbar;
|
|
@@ -89,6 +96,7 @@ public class WebViewDialog extends Dialog {
|
|
|
89
96
|
new HashMap<>();
|
|
90
97
|
private final ExecutorService executorService =
|
|
91
98
|
Executors.newCachedThreadPool();
|
|
99
|
+
private int iconColor = Color.BLACK; // Default icon color
|
|
92
100
|
|
|
93
101
|
Semaphore preShowSemaphore = null;
|
|
94
102
|
String preShowError = null;
|
|
@@ -200,14 +208,78 @@ public class WebViewDialog extends Dialog {
|
|
|
200
208
|
setContentView(R.layout.activity_browser);
|
|
201
209
|
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
|
202
210
|
|
|
211
|
+
// Make status bar transparent
|
|
212
|
+
if (getWindow() != null) {
|
|
213
|
+
getWindow().setStatusBarColor(Color.TRANSPARENT);
|
|
214
|
+
|
|
215
|
+
// Add FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag to the window
|
|
216
|
+
getWindow()
|
|
217
|
+
.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
|
218
|
+
|
|
219
|
+
// On Android 30+ clear FLAG_TRANSLUCENT_STATUS flag
|
|
220
|
+
getWindow()
|
|
221
|
+
.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
|
222
|
+
}
|
|
223
|
+
|
|
203
224
|
WindowInsetsControllerCompat insetsController =
|
|
204
|
-
new WindowInsetsControllerCompat(
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
225
|
+
new WindowInsetsControllerCompat(
|
|
226
|
+
getWindow(),
|
|
227
|
+
getWindow() != null ? getWindow().getDecorView() : null
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
if (getWindow() != null) {
|
|
231
|
+
getWindow()
|
|
232
|
+
.getDecorView()
|
|
233
|
+
.post(() -> {
|
|
234
|
+
// Get status bar height
|
|
235
|
+
int statusBarHeight = 0;
|
|
236
|
+
int resourceId = getContext()
|
|
237
|
+
.getResources()
|
|
238
|
+
.getIdentifier("status_bar_height", "dimen", "android");
|
|
239
|
+
if (resourceId > 0) {
|
|
240
|
+
statusBarHeight = getContext()
|
|
241
|
+
.getResources()
|
|
242
|
+
.getDimensionPixelSize(resourceId);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Find the status bar color view
|
|
246
|
+
View statusBarColorView = findViewById(R.id.status_bar_color_view);
|
|
247
|
+
|
|
248
|
+
// Set the height of the status bar color view
|
|
249
|
+
if (statusBarColorView != null) {
|
|
250
|
+
statusBarColorView.getLayoutParams().height = statusBarHeight;
|
|
251
|
+
statusBarColorView.requestLayout();
|
|
252
|
+
|
|
253
|
+
// Set color based on toolbar color or dark mode
|
|
254
|
+
if (
|
|
255
|
+
_options.getToolbarColor() != null &&
|
|
256
|
+
!_options.getToolbarColor().isEmpty()
|
|
257
|
+
) {
|
|
258
|
+
try {
|
|
259
|
+
// Use explicitly provided toolbar color for status bar
|
|
260
|
+
int toolbarColor = Color.parseColor(_options.getToolbarColor());
|
|
261
|
+
statusBarColorView.setBackgroundColor(toolbarColor);
|
|
262
|
+
|
|
263
|
+
// Set status bar text to white or black based on background
|
|
264
|
+
boolean isDarkBackground = isDarkColor(toolbarColor);
|
|
265
|
+
insetsController.setAppearanceLightStatusBars(
|
|
266
|
+
!isDarkBackground
|
|
267
|
+
);
|
|
268
|
+
} catch (IllegalArgumentException e) {
|
|
269
|
+
// Fallback to default black if color parsing fails
|
|
270
|
+
statusBarColorView.setBackgroundColor(Color.BLACK);
|
|
271
|
+
insetsController.setAppearanceLightStatusBars(false);
|
|
272
|
+
}
|
|
273
|
+
} else {
|
|
274
|
+
// Follow system dark mode if no toolbar color provided
|
|
275
|
+
boolean isDarkTheme = isDarkThemeEnabled();
|
|
276
|
+
int statusBarColor = isDarkTheme ? Color.BLACK : Color.WHITE;
|
|
277
|
+
statusBarColorView.setBackgroundColor(statusBarColor);
|
|
278
|
+
insetsController.setAppearanceLightStatusBars(!isDarkTheme);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
}
|
|
211
283
|
|
|
212
284
|
getWindow()
|
|
213
285
|
.setLayout(
|
|
@@ -246,9 +318,25 @@ public class WebViewDialog extends Dialog {
|
|
|
246
318
|
ValueCallback<Uri[]> filePathCallback,
|
|
247
319
|
FileChooserParams fileChooserParams
|
|
248
320
|
) {
|
|
321
|
+
// Get the accept type safely
|
|
322
|
+
String acceptType = "*/*"; // Default to all file types
|
|
323
|
+
if (
|
|
324
|
+
fileChooserParams.getAcceptTypes() != null &&
|
|
325
|
+
fileChooserParams.getAcceptTypes().length > 0 &&
|
|
326
|
+
!TextUtils.isEmpty(fileChooserParams.getAcceptTypes()[0])
|
|
327
|
+
) {
|
|
328
|
+
acceptType = fileChooserParams.getAcceptTypes()[0];
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Check if the file chooser is already open
|
|
332
|
+
if (mFilePathCallback != null) {
|
|
333
|
+
mFilePathCallback.onReceiveValue(null);
|
|
334
|
+
mFilePathCallback = null;
|
|
335
|
+
}
|
|
336
|
+
|
|
249
337
|
openFileChooser(
|
|
250
338
|
filePathCallback,
|
|
251
|
-
|
|
339
|
+
acceptType,
|
|
252
340
|
fileChooserParams.getMode() == FileChooserParams.MODE_OPEN_MULTIPLE
|
|
253
341
|
);
|
|
254
342
|
return true;
|
|
@@ -433,16 +521,100 @@ public class WebViewDialog extends Dialog {
|
|
|
433
521
|
mFilePathCallback = filePathCallback;
|
|
434
522
|
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
|
435
523
|
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
|
436
|
-
|
|
524
|
+
|
|
525
|
+
// Fix MIME type handling
|
|
526
|
+
if (
|
|
527
|
+
acceptType == null ||
|
|
528
|
+
acceptType.isEmpty() ||
|
|
529
|
+
acceptType.equals("undefined")
|
|
530
|
+
) {
|
|
531
|
+
acceptType = "*/*";
|
|
532
|
+
} else {
|
|
533
|
+
// Handle common web input accept types
|
|
534
|
+
if (acceptType.equals("image/*")) {
|
|
535
|
+
// Keep as is - image/*
|
|
536
|
+
} else if (acceptType.contains("image/")) {
|
|
537
|
+
// Specific image type requested but keep it general for better compatibility
|
|
538
|
+
acceptType = "image/*";
|
|
539
|
+
} else if (
|
|
540
|
+
acceptType.equals("audio/*") || acceptType.contains("audio/")
|
|
541
|
+
) {
|
|
542
|
+
acceptType = "audio/*";
|
|
543
|
+
} else if (
|
|
544
|
+
acceptType.equals("video/*") || acceptType.contains("video/")
|
|
545
|
+
) {
|
|
546
|
+
acceptType = "video/*";
|
|
547
|
+
} else if (acceptType.startsWith(".") || acceptType.contains(",")) {
|
|
548
|
+
// Handle file extensions like ".pdf, .docx" by using a general mime type
|
|
549
|
+
if (acceptType.contains(".pdf")) {
|
|
550
|
+
acceptType = "application/pdf";
|
|
551
|
+
} else if (
|
|
552
|
+
acceptType.contains(".doc") || acceptType.contains(".docx")
|
|
553
|
+
) {
|
|
554
|
+
acceptType = "application/msword";
|
|
555
|
+
} else if (
|
|
556
|
+
acceptType.contains(".xls") || acceptType.contains(".xlsx")
|
|
557
|
+
) {
|
|
558
|
+
acceptType = "application/vnd.ms-excel";
|
|
559
|
+
} else if (
|
|
560
|
+
acceptType.contains(".txt") || acceptType.contains(".text")
|
|
561
|
+
) {
|
|
562
|
+
acceptType = "text/plain";
|
|
563
|
+
} else {
|
|
564
|
+
// Default for extension lists
|
|
565
|
+
acceptType = "*/*";
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
Log.d("InAppBrowser", "File picker using MIME type: " + acceptType);
|
|
571
|
+
intent.setType(acceptType);
|
|
437
572
|
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, isMultiple);
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
573
|
+
|
|
574
|
+
try {
|
|
575
|
+
activity.startActivityForResult(
|
|
576
|
+
Intent.createChooser(intent, "Select File"),
|
|
577
|
+
FILE_CHOOSER_REQUEST_CODE
|
|
578
|
+
);
|
|
579
|
+
} catch (ActivityNotFoundException e) {
|
|
580
|
+
// If no app can handle the specific MIME type, try with a more generic one
|
|
581
|
+
Log.e(
|
|
582
|
+
"InAppBrowser",
|
|
583
|
+
"No app available for type: " + acceptType + ", trying with */*"
|
|
584
|
+
);
|
|
585
|
+
intent.setType("*/*");
|
|
586
|
+
try {
|
|
587
|
+
activity.startActivityForResult(
|
|
588
|
+
Intent.createChooser(intent, "Select File"),
|
|
589
|
+
FILE_CHOOSER_REQUEST_CODE
|
|
590
|
+
);
|
|
591
|
+
} catch (ActivityNotFoundException ex) {
|
|
592
|
+
// If still failing, report error
|
|
593
|
+
Log.e("InAppBrowser", "No app can handle file picker", ex);
|
|
594
|
+
if (mFilePathCallback != null) {
|
|
595
|
+
mFilePathCallback.onReceiveValue(null);
|
|
596
|
+
mFilePathCallback = null;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
442
600
|
}
|
|
443
601
|
|
|
444
602
|
public void reload() {
|
|
445
|
-
_webView
|
|
603
|
+
if (_webView != null) {
|
|
604
|
+
// First stop any ongoing loading
|
|
605
|
+
_webView.stopLoading();
|
|
606
|
+
|
|
607
|
+
// Check if there's a URL to reload
|
|
608
|
+
if (_webView.getUrl() != null) {
|
|
609
|
+
// Reload the current page
|
|
610
|
+
_webView.reload();
|
|
611
|
+
Log.d("InAppBrowser", "Reloading page: " + _webView.getUrl());
|
|
612
|
+
} else if (_options != null && _options.getUrl() != null) {
|
|
613
|
+
// If webView URL is null but we have an initial URL, load that
|
|
614
|
+
setUrl(_options.getUrl());
|
|
615
|
+
Log.d("InAppBrowser", "Loading initial URL: " + _options.getUrl());
|
|
616
|
+
}
|
|
617
|
+
}
|
|
446
618
|
}
|
|
447
619
|
|
|
448
620
|
public void destroy() {
|
|
@@ -485,56 +657,72 @@ public class WebViewDialog extends Dialog {
|
|
|
485
657
|
}
|
|
486
658
|
|
|
487
659
|
private void setupToolbar() {
|
|
488
|
-
_toolbar =
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
_toolbar.setBackgroundColor(color);
|
|
496
|
-
_toolbar.findViewById(R.id.backButton).setBackgroundColor(color);
|
|
497
|
-
_toolbar.findViewById(R.id.forwardButton).setBackgroundColor(color);
|
|
498
|
-
_toolbar.findViewById(R.id.closeButton).setBackgroundColor(color);
|
|
499
|
-
_toolbar.findViewById(R.id.reloadButton).setBackgroundColor(color);
|
|
500
|
-
|
|
501
|
-
if (!TextUtils.isEmpty(_options.getTitle())) {
|
|
502
|
-
this.setTitle(_options.getTitle());
|
|
503
|
-
} else {
|
|
660
|
+
_toolbar = findViewById(R.id.tool_bar);
|
|
661
|
+
|
|
662
|
+
// Apply toolbar color early, for ALL toolbar types, before any view configuration
|
|
663
|
+
if (
|
|
664
|
+
_options.getToolbarColor() != null &&
|
|
665
|
+
!_options.getToolbarColor().isEmpty()
|
|
666
|
+
) {
|
|
504
667
|
try {
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
} catch (URISyntaxException e) {
|
|
508
|
-
this.setTitle(_options.getTitle());
|
|
509
|
-
}
|
|
510
|
-
}
|
|
668
|
+
int toolbarColor = Color.parseColor(_options.getToolbarColor());
|
|
669
|
+
_toolbar.setBackgroundColor(toolbarColor);
|
|
511
670
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
671
|
+
// Get toolbar title and ensure it gets the right color
|
|
672
|
+
TextView titleText = _toolbar.findViewById(R.id.titleText);
|
|
673
|
+
|
|
674
|
+
// Determine icon and text color
|
|
675
|
+
int iconColor;
|
|
676
|
+
if (
|
|
677
|
+
_options.getToolbarTextColor() != null &&
|
|
678
|
+
!_options.getToolbarTextColor().isEmpty()
|
|
679
|
+
) {
|
|
680
|
+
try {
|
|
681
|
+
iconColor = Color.parseColor(_options.getToolbarTextColor());
|
|
682
|
+
} catch (IllegalArgumentException e) {
|
|
683
|
+
// Fallback to automatic detection if parsing fails
|
|
684
|
+
boolean isDarkBackground = isDarkColor(toolbarColor);
|
|
685
|
+
iconColor = isDarkBackground ? Color.WHITE : Color.BLACK;
|
|
519
686
|
}
|
|
687
|
+
} else {
|
|
688
|
+
// No explicit toolbarTextColor, use automatic detection based on background
|
|
689
|
+
boolean isDarkBackground = isDarkColor(toolbarColor);
|
|
690
|
+
iconColor = isDarkBackground ? Color.WHITE : Color.BLACK;
|
|
520
691
|
}
|
|
521
|
-
}
|
|
522
|
-
);
|
|
523
692
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
693
|
+
// Store for later use with navigation buttons
|
|
694
|
+
this.iconColor = iconColor;
|
|
695
|
+
|
|
696
|
+
// Set title text color directly
|
|
697
|
+
titleText.setTextColor(iconColor);
|
|
698
|
+
|
|
699
|
+
// Apply colors to all buttons
|
|
700
|
+
applyColorToAllButtons(toolbarColor, iconColor);
|
|
701
|
+
|
|
702
|
+
// Also ensure status bar gets the color
|
|
703
|
+
if (getWindow() != null) {
|
|
704
|
+
// Set status bar color
|
|
705
|
+
getWindow().setStatusBarColor(toolbarColor);
|
|
706
|
+
|
|
707
|
+
// Determine proper status bar text color (light or dark icons)
|
|
708
|
+
boolean isDarkBackground = isDarkColor(toolbarColor);
|
|
709
|
+
WindowInsetsControllerCompat insetsController =
|
|
710
|
+
new WindowInsetsControllerCompat(
|
|
711
|
+
getWindow(),
|
|
712
|
+
getWindow().getDecorView()
|
|
713
|
+
);
|
|
714
|
+
insetsController.setAppearanceLightStatusBars(!isDarkBackground);
|
|
532
715
|
}
|
|
716
|
+
} catch (IllegalArgumentException e) {
|
|
717
|
+
Log.e(
|
|
718
|
+
"InAppBrowser",
|
|
719
|
+
"Invalid toolbar color: " + _options.getToolbarColor()
|
|
720
|
+
);
|
|
533
721
|
}
|
|
534
|
-
|
|
722
|
+
}
|
|
535
723
|
|
|
536
|
-
ImageButton
|
|
537
|
-
|
|
724
|
+
ImageButton closeButtonView = _toolbar.findViewById(R.id.closeButton);
|
|
725
|
+
closeButtonView.setOnClickListener(
|
|
538
726
|
new View.OnClickListener() {
|
|
539
727
|
@Override
|
|
540
728
|
public void onClick(View view) {
|
|
@@ -572,78 +760,292 @@ public class WebViewDialog extends Dialog {
|
|
|
572
760
|
);
|
|
573
761
|
|
|
574
762
|
if (_options.showArrow()) {
|
|
575
|
-
|
|
763
|
+
closeButtonView.setImageResource(R.drawable.arrow_back_enabled);
|
|
576
764
|
}
|
|
577
765
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
766
|
+
// Handle reload button visibility
|
|
767
|
+
if (
|
|
768
|
+
_options.getShowReloadButton() &&
|
|
769
|
+
!TextUtils.equals(_options.getToolbarType(), "activity")
|
|
770
|
+
) {
|
|
771
|
+
View reloadButtonView = _toolbar.findViewById(R.id.reloadButton);
|
|
772
|
+
reloadButtonView.setVisibility(View.VISIBLE);
|
|
773
|
+
reloadButtonView.setOnClickListener(
|
|
582
774
|
new View.OnClickListener() {
|
|
583
775
|
@Override
|
|
584
776
|
public void onClick(View view) {
|
|
585
|
-
_webView
|
|
777
|
+
if (_webView != null) {
|
|
778
|
+
// First stop any ongoing loading
|
|
779
|
+
_webView.stopLoading();
|
|
780
|
+
|
|
781
|
+
// Check if there's a URL to reload
|
|
782
|
+
if (_webView.getUrl() != null) {
|
|
783
|
+
// Reload the current page
|
|
784
|
+
_webView.reload();
|
|
785
|
+
Log.d("InAppBrowser", "Reloading page: " + _webView.getUrl());
|
|
786
|
+
} else if (_options.getUrl() != null) {
|
|
787
|
+
// If webView URL is null but we have an initial URL, load that
|
|
788
|
+
setUrl(_options.getUrl());
|
|
789
|
+
Log.d(
|
|
790
|
+
"InAppBrowser",
|
|
791
|
+
"Loading initial URL: " + _options.getUrl()
|
|
792
|
+
);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
586
795
|
}
|
|
587
796
|
}
|
|
588
797
|
);
|
|
798
|
+
} else {
|
|
799
|
+
View reloadButtonView = _toolbar.findViewById(R.id.reloadButton);
|
|
800
|
+
reloadButtonView.setVisibility(View.GONE);
|
|
589
801
|
}
|
|
590
802
|
|
|
591
803
|
if (TextUtils.equals(_options.getToolbarType(), "activity")) {
|
|
804
|
+
// Activity mode should ONLY have:
|
|
805
|
+
// 1. Close button
|
|
806
|
+
// 2. Share button (if shareSubject is provided)
|
|
807
|
+
|
|
808
|
+
// Hide all navigation buttons
|
|
592
809
|
_toolbar.findViewById(R.id.forwardButton).setVisibility(View.GONE);
|
|
593
810
|
_toolbar.findViewById(R.id.backButton).setVisibility(View.GONE);
|
|
811
|
+
|
|
812
|
+
// Hide buttonNearDone
|
|
594
813
|
ImageButton buttonNearDoneView = _toolbar.findViewById(
|
|
595
814
|
R.id.buttonNearDone
|
|
596
815
|
);
|
|
597
816
|
buttonNearDoneView.setVisibility(View.GONE);
|
|
598
|
-
|
|
817
|
+
|
|
818
|
+
// In activity mode, always make the share button visible by setting a default shareSubject if not provided
|
|
819
|
+
if (
|
|
820
|
+
_options.getShareSubject() == null ||
|
|
821
|
+
_options.getShareSubject().isEmpty()
|
|
822
|
+
) {
|
|
823
|
+
_options.setShareSubject("Share");
|
|
824
|
+
Log.d("InAppBrowser", "Activity mode: Setting default shareSubject");
|
|
825
|
+
}
|
|
826
|
+
// Status bar color is already set at the top of this method, no need to set again
|
|
827
|
+
|
|
828
|
+
// Share button visibility is handled separately later
|
|
599
829
|
} else if (TextUtils.equals(_options.getToolbarType(), "navigation")) {
|
|
600
830
|
ImageButton buttonNearDoneView = _toolbar.findViewById(
|
|
601
831
|
R.id.buttonNearDone
|
|
602
832
|
);
|
|
603
833
|
buttonNearDoneView.setVisibility(View.GONE);
|
|
604
|
-
//
|
|
834
|
+
// Status bar color is already set at the top of this method, no need to set again
|
|
605
835
|
} else if (TextUtils.equals(_options.getToolbarType(), "blank")) {
|
|
606
836
|
_toolbar.setVisibility(View.GONE);
|
|
837
|
+
|
|
838
|
+
// Also set window background color to match status bar for blank toolbar
|
|
839
|
+
View statusBarColorView = findViewById(R.id.status_bar_color_view);
|
|
840
|
+
if (
|
|
841
|
+
_options.getToolbarColor() != null &&
|
|
842
|
+
!_options.getToolbarColor().isEmpty()
|
|
843
|
+
) {
|
|
844
|
+
try {
|
|
845
|
+
int toolbarColor = Color.parseColor(_options.getToolbarColor());
|
|
846
|
+
if (getWindow() != null) {
|
|
847
|
+
getWindow().getDecorView().setBackgroundColor(toolbarColor);
|
|
848
|
+
}
|
|
849
|
+
// Also set status bar color view background if available
|
|
850
|
+
if (statusBarColorView != null) {
|
|
851
|
+
statusBarColorView.setBackgroundColor(toolbarColor);
|
|
852
|
+
}
|
|
853
|
+
} catch (IllegalArgumentException e) {
|
|
854
|
+
// Fallback to system default if color parsing fails
|
|
855
|
+
boolean isDarkTheme = isDarkThemeEnabled();
|
|
856
|
+
int windowBackgroundColor = isDarkTheme ? Color.BLACK : Color.WHITE;
|
|
857
|
+
if (getWindow() != null) {
|
|
858
|
+
getWindow()
|
|
859
|
+
.getDecorView()
|
|
860
|
+
.setBackgroundColor(windowBackgroundColor);
|
|
861
|
+
}
|
|
862
|
+
// Also set status bar color view background if available
|
|
863
|
+
if (statusBarColorView != null) {
|
|
864
|
+
statusBarColorView.setBackgroundColor(windowBackgroundColor);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
} else {
|
|
868
|
+
// Follow system dark mode
|
|
869
|
+
boolean isDarkTheme = isDarkThemeEnabled();
|
|
870
|
+
int windowBackgroundColor = isDarkTheme ? Color.BLACK : Color.WHITE;
|
|
871
|
+
if (getWindow() != null) {
|
|
872
|
+
getWindow().getDecorView().setBackgroundColor(windowBackgroundColor);
|
|
873
|
+
}
|
|
874
|
+
// Also set status bar color view background if available
|
|
875
|
+
if (statusBarColorView != null) {
|
|
876
|
+
statusBarColorView.setBackgroundColor(windowBackgroundColor);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
607
879
|
} else {
|
|
608
880
|
_toolbar.findViewById(R.id.forwardButton).setVisibility(View.GONE);
|
|
609
881
|
_toolbar.findViewById(R.id.backButton).setVisibility(View.GONE);
|
|
610
882
|
|
|
883
|
+
// Status bar color is already set at the top of this method, no need to set again
|
|
884
|
+
|
|
611
885
|
Options.ButtonNearDone buttonNearDone = _options.getButtonNearDone();
|
|
612
886
|
if (buttonNearDone != null) {
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
try {
|
|
618
|
-
ImageButton buttonNearDoneView = _toolbar.findViewById(
|
|
619
|
-
R.id.buttonNearDone
|
|
620
|
-
);
|
|
621
|
-
buttonNearDoneView.setVisibility(View.VISIBLE);
|
|
622
|
-
|
|
623
|
-
inputStream = assetManager.open(buttonNearDone.getIcon());
|
|
887
|
+
ImageButton buttonNearDoneView = _toolbar.findViewById(
|
|
888
|
+
R.id.buttonNearDone
|
|
889
|
+
);
|
|
890
|
+
buttonNearDoneView.setVisibility(View.VISIBLE);
|
|
624
891
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
892
|
+
// Handle different icon types
|
|
893
|
+
String iconType = buttonNearDone.getIconType();
|
|
894
|
+
if ("vector".equals(iconType)) {
|
|
895
|
+
// Use native Android vector drawable
|
|
896
|
+
try {
|
|
897
|
+
String iconName = buttonNearDone.getIcon();
|
|
898
|
+
// Convert name to Android resource ID (remove file extension if present)
|
|
899
|
+
if (iconName.endsWith(".xml")) {
|
|
900
|
+
iconName = iconName.substring(0, iconName.length() - 4);
|
|
901
|
+
}
|
|
631
902
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
903
|
+
// Get resource ID
|
|
904
|
+
int resourceId = _context
|
|
905
|
+
.getResources()
|
|
906
|
+
.getIdentifier(iconName, "drawable", _context.getPackageName());
|
|
907
|
+
|
|
908
|
+
if (resourceId != 0) {
|
|
909
|
+
// Set the vector drawable
|
|
910
|
+
buttonNearDoneView.setImageResource(resourceId);
|
|
911
|
+
// Apply color filter
|
|
912
|
+
buttonNearDoneView.setColorFilter(iconColor);
|
|
913
|
+
Log.d(
|
|
914
|
+
"InAppBrowser",
|
|
915
|
+
"Successfully loaded vector drawable: " + iconName
|
|
916
|
+
);
|
|
917
|
+
} else {
|
|
918
|
+
Log.e(
|
|
919
|
+
"InAppBrowser",
|
|
920
|
+
"Vector drawable not found: " + iconName + ", using fallback"
|
|
921
|
+
);
|
|
922
|
+
// Fallback to a common system icon
|
|
923
|
+
buttonNearDoneView.setImageResource(
|
|
924
|
+
android.R.drawable.ic_menu_info_details
|
|
925
|
+
);
|
|
926
|
+
buttonNearDoneView.setColorFilter(iconColor);
|
|
927
|
+
}
|
|
928
|
+
} catch (Exception e) {
|
|
929
|
+
Log.e(
|
|
930
|
+
"InAppBrowser",
|
|
931
|
+
"Error loading vector drawable: " + e.getMessage()
|
|
932
|
+
);
|
|
933
|
+
// Fallback to a common system icon
|
|
934
|
+
buttonNearDoneView.setImageResource(
|
|
935
|
+
android.R.drawable.ic_menu_info_details
|
|
936
|
+
);
|
|
937
|
+
buttonNearDoneView.setColorFilter(iconColor);
|
|
938
|
+
}
|
|
939
|
+
} else if ("asset".equals(iconType)) {
|
|
940
|
+
// Handle SVG from assets
|
|
941
|
+
AssetManager assetManager = _context.getAssets();
|
|
942
|
+
InputStream inputStream = null;
|
|
943
|
+
try {
|
|
944
|
+
// Try to load from public folder first
|
|
945
|
+
String iconPath = "public/" + buttonNearDone.getIcon();
|
|
640
946
|
try {
|
|
641
|
-
inputStream.
|
|
947
|
+
inputStream = assetManager.open(iconPath);
|
|
642
948
|
} catch (IOException e) {
|
|
643
|
-
|
|
949
|
+
// If not found in public, try root assets
|
|
950
|
+
try {
|
|
951
|
+
inputStream = assetManager.open(buttonNearDone.getIcon());
|
|
952
|
+
} catch (IOException e2) {
|
|
953
|
+
Log.e(
|
|
954
|
+
"InAppBrowser",
|
|
955
|
+
"SVG file not found in assets: " + buttonNearDone.getIcon()
|
|
956
|
+
);
|
|
957
|
+
buttonNearDoneView.setVisibility(View.GONE);
|
|
958
|
+
return;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
if (inputStream == null) {
|
|
963
|
+
Log.e(
|
|
964
|
+
"InAppBrowser",
|
|
965
|
+
"Failed to load SVG icon: " + buttonNearDone.getIcon()
|
|
966
|
+
);
|
|
967
|
+
buttonNearDoneView.setVisibility(View.GONE);
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
// Parse and render SVG
|
|
972
|
+
SVG svg = SVG.getFromInputStream(inputStream);
|
|
973
|
+
if (svg == null) {
|
|
974
|
+
Log.e(
|
|
975
|
+
"InAppBrowser",
|
|
976
|
+
"Failed to parse SVG icon: " + buttonNearDone.getIcon()
|
|
977
|
+
);
|
|
978
|
+
buttonNearDoneView.setVisibility(View.GONE);
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// Get the dimensions from options or use SVG's size
|
|
983
|
+
float width = buttonNearDone.getWidth() > 0
|
|
984
|
+
? buttonNearDone.getWidth()
|
|
985
|
+
: 24;
|
|
986
|
+
float height = buttonNearDone.getHeight() > 0
|
|
987
|
+
? buttonNearDone.getHeight()
|
|
988
|
+
: 24;
|
|
989
|
+
|
|
990
|
+
// Get density for proper scaling
|
|
991
|
+
float density = _context.getResources().getDisplayMetrics().density;
|
|
992
|
+
int targetWidth = Math.round(width * density);
|
|
993
|
+
int targetHeight = Math.round(height * density);
|
|
994
|
+
|
|
995
|
+
// Set document size
|
|
996
|
+
svg.setDocumentWidth(targetWidth);
|
|
997
|
+
svg.setDocumentHeight(targetHeight);
|
|
998
|
+
|
|
999
|
+
// Create a bitmap and render SVG to it for better quality
|
|
1000
|
+
Bitmap bitmap = Bitmap.createBitmap(
|
|
1001
|
+
targetWidth,
|
|
1002
|
+
targetHeight,
|
|
1003
|
+
Bitmap.Config.ARGB_8888
|
|
1004
|
+
);
|
|
1005
|
+
Canvas canvas = new Canvas(bitmap);
|
|
1006
|
+
svg.renderToCanvas(canvas);
|
|
1007
|
+
|
|
1008
|
+
// Apply color filter to the bitmap
|
|
1009
|
+
Paint paint = new Paint();
|
|
1010
|
+
paint.setColorFilter(
|
|
1011
|
+
new PorterDuffColorFilter(iconColor, PorterDuff.Mode.SRC_IN)
|
|
1012
|
+
);
|
|
1013
|
+
Canvas colorFilterCanvas = new Canvas(bitmap);
|
|
1014
|
+
colorFilterCanvas.drawBitmap(bitmap, 0, 0, paint);
|
|
1015
|
+
|
|
1016
|
+
// Set the colored bitmap as image
|
|
1017
|
+
buttonNearDoneView.setImageBitmap(bitmap);
|
|
1018
|
+
buttonNearDoneView.setScaleType(ImageView.ScaleType.FIT_CENTER);
|
|
1019
|
+
buttonNearDoneView.setPadding(12, 12, 12, 12); // Standard button padding
|
|
1020
|
+
} catch (SVGParseException e) {
|
|
1021
|
+
Log.e(
|
|
1022
|
+
"InAppBrowser",
|
|
1023
|
+
"Error loading SVG icon: " + e.getMessage(),
|
|
1024
|
+
e
|
|
1025
|
+
);
|
|
1026
|
+
buttonNearDoneView.setVisibility(View.GONE);
|
|
1027
|
+
} finally {
|
|
1028
|
+
if (inputStream != null) {
|
|
1029
|
+
try {
|
|
1030
|
+
inputStream.close();
|
|
1031
|
+
} catch (IOException e) {
|
|
1032
|
+
Log.e(
|
|
1033
|
+
"InAppBrowser",
|
|
1034
|
+
"Error closing input stream: " + e.getMessage()
|
|
1035
|
+
);
|
|
1036
|
+
}
|
|
644
1037
|
}
|
|
645
1038
|
}
|
|
1039
|
+
} else {
|
|
1040
|
+
// Default fallback or unsupported type
|
|
1041
|
+
Log.e("InAppBrowser", "Unsupported icon type: " + iconType);
|
|
1042
|
+
buttonNearDoneView.setVisibility(View.GONE);
|
|
646
1043
|
}
|
|
1044
|
+
|
|
1045
|
+
// Set the click listener
|
|
1046
|
+
buttonNearDoneView.setOnClickListener(view ->
|
|
1047
|
+
_options.getCallbacks().buttonNearDoneClicked()
|
|
1048
|
+
);
|
|
647
1049
|
} else {
|
|
648
1050
|
ImageButton buttonNearDoneView = _toolbar.findViewById(
|
|
649
1051
|
R.id.buttonNearDone
|
|
@@ -651,6 +1053,94 @@ public class WebViewDialog extends Dialog {
|
|
|
651
1053
|
buttonNearDoneView.setVisibility(View.GONE);
|
|
652
1054
|
}
|
|
653
1055
|
}
|
|
1056
|
+
|
|
1057
|
+
// Add share button functionality
|
|
1058
|
+
ImageButton shareButton = _toolbar.findViewById(R.id.shareButton);
|
|
1059
|
+
if (
|
|
1060
|
+
_options.getShareSubject() != null &&
|
|
1061
|
+
!_options.getShareSubject().isEmpty()
|
|
1062
|
+
) {
|
|
1063
|
+
shareButton.setVisibility(View.VISIBLE);
|
|
1064
|
+
Log.d(
|
|
1065
|
+
"InAppBrowser",
|
|
1066
|
+
"Share button should be visible, shareSubject: " +
|
|
1067
|
+
_options.getShareSubject()
|
|
1068
|
+
);
|
|
1069
|
+
|
|
1070
|
+
// Apply the same color filter as other buttons to ensure visibility
|
|
1071
|
+
shareButton.setColorFilter(iconColor);
|
|
1072
|
+
|
|
1073
|
+
// The color filter is now applied in applyColorToAllButtons
|
|
1074
|
+
shareButton.setOnClickListener(view -> {
|
|
1075
|
+
JSObject shareDisclaimer = _options.getShareDisclaimer();
|
|
1076
|
+
if (shareDisclaimer != null) {
|
|
1077
|
+
new AlertDialog.Builder(_context)
|
|
1078
|
+
.setTitle(shareDisclaimer.getString("title", "Title"))
|
|
1079
|
+
.setMessage(shareDisclaimer.getString("message", "Message"))
|
|
1080
|
+
.setPositiveButton(
|
|
1081
|
+
shareDisclaimer.getString("confirmBtn", "Confirm"),
|
|
1082
|
+
(dialog, which) -> {
|
|
1083
|
+
_options.getCallbacks().confirmBtnClicked();
|
|
1084
|
+
shareUrl();
|
|
1085
|
+
}
|
|
1086
|
+
)
|
|
1087
|
+
.setNegativeButton(
|
|
1088
|
+
shareDisclaimer.getString("cancelBtn", "Cancel"),
|
|
1089
|
+
null
|
|
1090
|
+
)
|
|
1091
|
+
.show();
|
|
1092
|
+
} else {
|
|
1093
|
+
shareUrl();
|
|
1094
|
+
}
|
|
1095
|
+
});
|
|
1096
|
+
} else {
|
|
1097
|
+
shareButton.setVisibility(View.GONE);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
// Also color the title text
|
|
1101
|
+
TextView titleText = _toolbar.findViewById(R.id.titleText);
|
|
1102
|
+
if (titleText != null) {
|
|
1103
|
+
titleText.setTextColor(iconColor);
|
|
1104
|
+
|
|
1105
|
+
// Set the title text
|
|
1106
|
+
if (!TextUtils.isEmpty(_options.getTitle())) {
|
|
1107
|
+
this.setTitle(_options.getTitle());
|
|
1108
|
+
} else {
|
|
1109
|
+
try {
|
|
1110
|
+
URI uri = new URI(_options.getUrl());
|
|
1111
|
+
this.setTitle(uri.getHost());
|
|
1112
|
+
} catch (URISyntaxException e) {
|
|
1113
|
+
this.setTitle(_options.getTitle());
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
/**
|
|
1120
|
+
* Applies background and tint colors to all buttons in the toolbar
|
|
1121
|
+
*/
|
|
1122
|
+
private void applyColorToAllButtons(int backgroundColor, int iconColor) {
|
|
1123
|
+
// Get all buttons
|
|
1124
|
+
ImageButton backButton = _toolbar.findViewById(R.id.backButton);
|
|
1125
|
+
ImageButton forwardButton = _toolbar.findViewById(R.id.forwardButton);
|
|
1126
|
+
ImageButton closeButton = _toolbar.findViewById(R.id.closeButton);
|
|
1127
|
+
ImageButton reloadButton = _toolbar.findViewById(R.id.reloadButton);
|
|
1128
|
+
ImageButton shareButton = _toolbar.findViewById(R.id.shareButton);
|
|
1129
|
+
ImageButton buttonNearDoneView = _toolbar.findViewById(R.id.buttonNearDone);
|
|
1130
|
+
|
|
1131
|
+
// Set button backgrounds
|
|
1132
|
+
backButton.setBackgroundColor(backgroundColor);
|
|
1133
|
+
forwardButton.setBackgroundColor(backgroundColor);
|
|
1134
|
+
closeButton.setBackgroundColor(backgroundColor);
|
|
1135
|
+
reloadButton.setBackgroundColor(backgroundColor);
|
|
1136
|
+
|
|
1137
|
+
// Apply tint colors to buttons
|
|
1138
|
+
backButton.setColorFilter(iconColor);
|
|
1139
|
+
forwardButton.setColorFilter(iconColor);
|
|
1140
|
+
closeButton.setColorFilter(iconColor);
|
|
1141
|
+
reloadButton.setColorFilter(iconColor);
|
|
1142
|
+
shareButton.setColorFilter(iconColor);
|
|
1143
|
+
buttonNearDoneView.setColorFilter(iconColor);
|
|
654
1144
|
}
|
|
655
1145
|
|
|
656
1146
|
public void handleProxyResultError(String result, String id) {
|
|
@@ -840,7 +1330,7 @@ public class WebViewDialog extends Dialog {
|
|
|
840
1330
|
);
|
|
841
1331
|
}
|
|
842
1332
|
String s = String.format(
|
|
843
|
-
"try {function getHeaders() {const h = {}; %s return h}; window.InAppBrowserProxyRequest(new Request(atob('%s'), {headers: getHeaders(), method: '%s'})).then(async (res) => Capacitor.Plugins.InAppBrowser.lsuakdchgbbaHandleProxiedRequest({ok: true, result: (!!res ? {headers: Object.fromEntries(res.headers.entries()), code: res.status, body: (await res.text())} : null), id: '%s'})).catch((e) => Capacitor.Plugins.InAppBrowser.lsuakdchgbbaHandleProxiedRequest({ok: false, result: e.toString(), id: '%s'})
|
|
1333
|
+
"try {function getHeaders() {const h = {}; %s return h}; window.InAppBrowserProxyRequest(new Request(atob('%s'), {headers: getHeaders(), method: '%s'})).then(async (res) => Capacitor.Plugins.InAppBrowser.lsuakdchgbbaHandleProxiedRequest({ok: true, result: (!!res ? {headers: Object.fromEntries(res.headers.entries()), code: res.status, body: (await res.text())} : null), id: '%s'})).catch((e) => Capacitor.Plugins.InAppBrowser.lsuakdchgbbaHandleProxiedRequest({ok: false, result: e.toString(), id: '%s'})} catch (e) {Capacitor.Plugins.InAppBrowser.lsuakdchgbbaHandleProxiedRequest({ok: false, result: e.toString(), id: '%s'})}",
|
|
844
1334
|
headers,
|
|
845
1335
|
toBase64(request.getUrl().toString()),
|
|
846
1336
|
request.getMethod(),
|
|
@@ -1023,18 +1513,36 @@ public class WebViewDialog extends Dialog {
|
|
|
1023
1513
|
if (_webView.canGoBack()) {
|
|
1024
1514
|
backButton.setImageResource(R.drawable.arrow_back_enabled);
|
|
1025
1515
|
backButton.setEnabled(true);
|
|
1516
|
+
backButton.setColorFilter(iconColor);
|
|
1026
1517
|
} else {
|
|
1027
1518
|
backButton.setImageResource(R.drawable.arrow_back_disabled);
|
|
1028
1519
|
backButton.setEnabled(false);
|
|
1520
|
+
backButton.setColorFilter(
|
|
1521
|
+
Color.argb(
|
|
1522
|
+
128,
|
|
1523
|
+
Color.red(iconColor),
|
|
1524
|
+
Color.green(iconColor),
|
|
1525
|
+
Color.blue(iconColor)
|
|
1526
|
+
)
|
|
1527
|
+
);
|
|
1029
1528
|
}
|
|
1030
1529
|
|
|
1031
1530
|
ImageButton forwardButton = _toolbar.findViewById(R.id.forwardButton);
|
|
1032
1531
|
if (_webView.canGoForward()) {
|
|
1033
1532
|
forwardButton.setImageResource(R.drawable.arrow_forward_enabled);
|
|
1034
1533
|
forwardButton.setEnabled(true);
|
|
1534
|
+
forwardButton.setColorFilter(iconColor);
|
|
1035
1535
|
} else {
|
|
1036
1536
|
forwardButton.setImageResource(R.drawable.arrow_forward_disabled);
|
|
1037
1537
|
forwardButton.setEnabled(false);
|
|
1538
|
+
forwardButton.setColorFilter(
|
|
1539
|
+
Color.argb(
|
|
1540
|
+
128,
|
|
1541
|
+
Color.red(iconColor),
|
|
1542
|
+
Color.green(iconColor),
|
|
1543
|
+
Color.blue(iconColor)
|
|
1544
|
+
)
|
|
1545
|
+
);
|
|
1038
1546
|
}
|
|
1039
1547
|
|
|
1040
1548
|
_options.getCallbacks().pageLoaded();
|
|
@@ -1180,4 +1688,51 @@ public class WebViewDialog extends Dialog {
|
|
|
1180
1688
|
proxiedRequestsHashmap.remove(key);
|
|
1181
1689
|
}
|
|
1182
1690
|
}
|
|
1691
|
+
|
|
1692
|
+
private void shareUrl() {
|
|
1693
|
+
Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
|
1694
|
+
shareIntent.setType("text/plain");
|
|
1695
|
+
shareIntent.putExtra(Intent.EXTRA_SUBJECT, _options.getShareSubject());
|
|
1696
|
+
shareIntent.putExtra(Intent.EXTRA_TEXT, _options.getUrl());
|
|
1697
|
+
_context.startActivity(Intent.createChooser(shareIntent, "Share"));
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
private boolean isDarkColor(int color) {
|
|
1701
|
+
int red = Color.red(color);
|
|
1702
|
+
int green = Color.green(color);
|
|
1703
|
+
int blue = Color.blue(color);
|
|
1704
|
+
double luminance = (0.299 * red + 0.587 * green + 0.114 * blue) / 255.0;
|
|
1705
|
+
return luminance < 0.5;
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
private boolean isDarkThemeEnabled() {
|
|
1709
|
+
// This method checks if dark theme is currently enabled without using Configuration class
|
|
1710
|
+
try {
|
|
1711
|
+
// On Android 10+, check via resources for night mode
|
|
1712
|
+
Resources.Theme theme = _context.getTheme();
|
|
1713
|
+
TypedValue typedValue = new TypedValue();
|
|
1714
|
+
|
|
1715
|
+
if (
|
|
1716
|
+
theme.resolveAttribute(android.R.attr.isLightTheme, typedValue, true)
|
|
1717
|
+
) {
|
|
1718
|
+
// isLightTheme exists - returns true if light, false if dark
|
|
1719
|
+
return typedValue.data != 1;
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
// Fallback method - check background color of window
|
|
1723
|
+
if (
|
|
1724
|
+
theme.resolveAttribute(
|
|
1725
|
+
android.R.attr.windowBackground,
|
|
1726
|
+
typedValue,
|
|
1727
|
+
true
|
|
1728
|
+
)
|
|
1729
|
+
) {
|
|
1730
|
+
int backgroundColor = typedValue.data;
|
|
1731
|
+
return isDarkColor(backgroundColor);
|
|
1732
|
+
}
|
|
1733
|
+
} catch (Exception e) {
|
|
1734
|
+
// Ignore and fallback to light theme
|
|
1735
|
+
}
|
|
1736
|
+
return false;
|
|
1737
|
+
}
|
|
1183
1738
|
}
|