@capgo/capacitor-native-navigation 8.0.15 → 8.0.17
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.
|
@@ -44,9 +44,11 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
44
44
|
private var tabBar: UITabBar?
|
|
45
45
|
private var tabBarController: NativeNavigationTabController?
|
|
46
46
|
private var tabViewControllers: [UIViewController] = []
|
|
47
|
+
private weak var systemTabRootContainer: UIView?
|
|
47
48
|
private weak var originalWebViewSuperview: UIView?
|
|
48
49
|
private var originalWebViewIndex: Int?
|
|
49
50
|
private var originalWebViewAutoresizingMask: UIView.AutoresizingMask?
|
|
51
|
+
private var liftedWebViewOverlays: [NativeNavigationWeakView] = []
|
|
50
52
|
private var isWebViewHostedInSystemTabController = false
|
|
51
53
|
private var navbarHeight: CGFloat = 44
|
|
52
54
|
private var tabbarHeight: CGFloat = 64
|
|
@@ -437,6 +439,13 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
437
439
|
notifyTabSelect(index: item.tag)
|
|
438
440
|
}
|
|
439
441
|
|
|
442
|
+
public func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
|
|
443
|
+
if usesSystemLiquidGlass {
|
|
444
|
+
hostWebView(in: viewController)
|
|
445
|
+
}
|
|
446
|
+
return true
|
|
447
|
+
}
|
|
448
|
+
|
|
440
449
|
public func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
|
|
441
450
|
guard !suppressTabSelectEvent else {
|
|
442
451
|
hostWebViewInSelectedSystemTab()
|
|
@@ -552,43 +561,108 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
552
561
|
controller.view.isHidden = !tabbarVisible
|
|
553
562
|
|
|
554
563
|
if let parent = bridge?.viewController {
|
|
564
|
+
let containerView = systemTabHostingContainerView(in: parent)
|
|
555
565
|
parent.addChild(controller)
|
|
556
|
-
insertSystemTabControllerView(controller.view, in:
|
|
566
|
+
insertSystemTabControllerView(controller.view, in: containerView)
|
|
557
567
|
controller.didMove(toParent: parent)
|
|
558
568
|
}
|
|
559
569
|
|
|
560
570
|
self.tabBarController = controller
|
|
561
571
|
self.tabBar = controller.tabBar
|
|
572
|
+
liftWebViewOverlaysAboveSystemTabs()
|
|
562
573
|
hostWebViewInSelectedSystemTab()
|
|
563
574
|
return controller.tabBar
|
|
564
575
|
}
|
|
565
576
|
|
|
577
|
+
private func systemTabHostingContainerView(in parent: UIViewController) -> UIView {
|
|
578
|
+
if let systemTabRootContainer = systemTabRootContainer {
|
|
579
|
+
return systemTabRootContainer
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
guard let webView = webView,
|
|
583
|
+
parent.view === webView else {
|
|
584
|
+
return parent.view
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
let previousSuperview = webView.superview
|
|
588
|
+
let previousIndex = previousSuperview?.subviews.firstIndex(of: webView)
|
|
589
|
+
let previousFrame = webView.frame
|
|
590
|
+
let previousAutoresizingMask = webView.autoresizingMask
|
|
591
|
+
let container = UIView(frame: previousFrame)
|
|
592
|
+
container.backgroundColor = nativeNavigationFallbackBackground(for: webView)
|
|
593
|
+
container.isOpaque = true
|
|
594
|
+
container.autoresizingMask = previousAutoresizingMask.isEmpty ? [.flexibleWidth, .flexibleHeight] : previousAutoresizingMask
|
|
595
|
+
|
|
596
|
+
if let previousSuperview = previousSuperview {
|
|
597
|
+
previousSuperview.insertSubview(container, at: min(previousIndex ?? previousSuperview.subviews.count, previousSuperview.subviews.count))
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
parent.view = container
|
|
601
|
+
container.addSubview(webView)
|
|
602
|
+
webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
603
|
+
webView.frame = container.bounds
|
|
604
|
+
moveNativeChrome(from: webView, to: container)
|
|
605
|
+
|
|
606
|
+
systemTabRootContainer = container
|
|
607
|
+
originalWebViewSuperview = container
|
|
608
|
+
originalWebViewIndex = 0
|
|
609
|
+
originalWebViewAutoresizingMask = webView.autoresizingMask
|
|
610
|
+
liftWebViewOverlaysAboveSystemTabs()
|
|
611
|
+
return container
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
private func moveNativeChrome(from webView: UIView, to container: UIView) {
|
|
615
|
+
if let navContainer = navContainer,
|
|
616
|
+
navContainer.superview === webView {
|
|
617
|
+
container.addSubview(navContainer)
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
|
|
566
621
|
private func applySystemTabBarItems(_ items: [UITabBarItem], selectedIndex: Int?, animated: Bool) {
|
|
567
622
|
guard let tabBarController = tabBarController else {
|
|
568
623
|
return
|
|
569
624
|
}
|
|
570
625
|
|
|
571
626
|
let previousSelectedIndex = tabBarController.selectedIndex
|
|
572
|
-
let controllers = items
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
627
|
+
let controllers = systemTabContentControllers(for: items)
|
|
628
|
+
let currentControllers = tabBarController.viewControllers ?? []
|
|
629
|
+
let shouldUpdateControllers = currentControllers.count != controllers.count
|
|
630
|
+
|| zip(currentControllers, controllers).contains { currentController, nextController in
|
|
631
|
+
currentController !== nextController
|
|
632
|
+
}
|
|
577
633
|
let shouldAnimate = animated && tabBarController.viewControllers?.count == controllers.count
|
|
578
634
|
|
|
579
635
|
suppressTabSelectEvent = true
|
|
580
|
-
|
|
636
|
+
if shouldUpdateControllers {
|
|
637
|
+
tabBarController.setViewControllers(controllers, animated: shouldAnimate)
|
|
638
|
+
}
|
|
581
639
|
if !controllers.isEmpty {
|
|
582
640
|
let fallbackIndex = selectedIndex ?? previousSelectedIndex
|
|
583
641
|
let index = min(max(fallbackIndex, 0), controllers.count - 1)
|
|
642
|
+
hostWebView(in: controllers[index])
|
|
584
643
|
tabBarController.selectedIndex = index
|
|
585
644
|
}
|
|
586
|
-
hostWebViewInSelectedSystemTab()
|
|
587
645
|
suppressTabSelectEvent = false
|
|
588
646
|
|
|
589
647
|
tabViewControllers = controllers
|
|
590
648
|
}
|
|
591
649
|
|
|
650
|
+
private func systemTabContentControllers(for items: [UITabBarItem]) -> [UIViewController] {
|
|
651
|
+
let existingControllers = tabViewControllers.compactMap { $0 as? NativeNavigationTabContentController }
|
|
652
|
+
if existingControllers.count == items.count {
|
|
653
|
+
zip(existingControllers, items).forEach { controller, item in
|
|
654
|
+
controller.tabBarItem = item
|
|
655
|
+
}
|
|
656
|
+
return existingControllers
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
return items.map { item -> UIViewController in
|
|
660
|
+
let controller = NativeNavigationTabContentController()
|
|
661
|
+
controller.tabBarItem = item
|
|
662
|
+
return controller
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
592
666
|
private func setSystemTabBarHidden(_ hidden: Bool) {
|
|
593
667
|
guard let tabBarController = tabBarController else {
|
|
594
668
|
return
|
|
@@ -617,6 +691,7 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
617
691
|
tabBarController?.view.isHidden = false
|
|
618
692
|
if usesSystemLiquidGlass {
|
|
619
693
|
setSystemTabBarHidden(false)
|
|
694
|
+
liftWebViewOverlaysAboveSystemTabs()
|
|
620
695
|
hostWebViewInSelectedSystemTab()
|
|
621
696
|
} else {
|
|
622
697
|
tabBar.isHidden = false
|
|
@@ -671,17 +746,53 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
671
746
|
}
|
|
672
747
|
|
|
673
748
|
private func hostWebViewInSelectedSystemTab() {
|
|
749
|
+
hostWebView(in: tabBarController?.selectedViewController)
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
private func hostWebView(in viewController: UIViewController?) {
|
|
674
753
|
guard usesSystemLiquidGlass,
|
|
675
754
|
let webView = webView,
|
|
676
|
-
let selectedController =
|
|
755
|
+
let selectedController = viewController as? NativeNavigationTabContentController else {
|
|
677
756
|
return
|
|
678
757
|
}
|
|
679
758
|
|
|
759
|
+
liftWebViewOverlaysAboveSystemTabs()
|
|
680
760
|
captureOriginalWebViewPlacementIfNeeded(webView)
|
|
681
|
-
clearHostedWebViews(matching: webView, except: selectedController)
|
|
682
|
-
selectedController.host(webView: webView)
|
|
761
|
+
clearHostedWebViews(matching: webView, except: selectedController, preservingSnapshots: true)
|
|
762
|
+
guard selectedController.host(webView: webView) else {
|
|
763
|
+
isWebViewHostedInSystemTabController = false
|
|
764
|
+
return
|
|
765
|
+
}
|
|
683
766
|
clearHostedWebViews(matching: webView, except: selectedController)
|
|
684
767
|
isWebViewHostedInSystemTabController = true
|
|
768
|
+
bringLiftedWebViewOverlaysToFront()
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
private func liftWebViewOverlaysAboveSystemTabs() {
|
|
772
|
+
guard usesSystemLiquidGlass,
|
|
773
|
+
let webView = webView,
|
|
774
|
+
let container = systemTabRootContainer else {
|
|
775
|
+
return
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
nativeNavigationLiftWebViewOverlaySubviews(
|
|
779
|
+
from: webView,
|
|
780
|
+
to: container,
|
|
781
|
+
tracking: &liftedWebViewOverlays,
|
|
782
|
+
excluding: [navContainer, tabContainer, tabBarController?.view]
|
|
783
|
+
)
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
private func bringLiftedWebViewOverlaysToFront() {
|
|
787
|
+
guard let container = systemTabRootContainer else {
|
|
788
|
+
return
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
liftedWebViewOverlays = liftedWebViewOverlays.filter { $0.value != nil }
|
|
792
|
+
liftedWebViewOverlays
|
|
793
|
+
.compactMap(\.value)
|
|
794
|
+
.filter { $0.superview === container }
|
|
795
|
+
.forEach { container.bringSubviewToFront($0) }
|
|
685
796
|
}
|
|
686
797
|
|
|
687
798
|
private func restoreWebViewFromSystemTabController() {
|
|
@@ -700,11 +811,15 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
700
811
|
isWebViewHostedInSystemTabController = false
|
|
701
812
|
}
|
|
702
813
|
|
|
703
|
-
private func clearHostedWebViews(
|
|
814
|
+
private func clearHostedWebViews(
|
|
815
|
+
matching webView: UIView,
|
|
816
|
+
except owner: NativeNavigationTabContentController? = nil,
|
|
817
|
+
preservingSnapshots: Bool = false
|
|
818
|
+
) {
|
|
704
819
|
tabViewControllers
|
|
705
820
|
.compactMap { $0 as? NativeNavigationTabContentController }
|
|
706
821
|
.filter { $0 !== owner }
|
|
707
|
-
.forEach { $0.clearHostedWebView(ifMatching: webView) }
|
|
822
|
+
.forEach { $0.clearHostedWebView(ifMatching: webView, preservingSnapshot: preservingSnapshots) }
|
|
708
823
|
}
|
|
709
824
|
|
|
710
825
|
private func makeBarButtonItems(_ rawItems: [[String: Any]], placement: String) -> [UIBarButtonItem] {
|
|
@@ -900,12 +1015,12 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
900
1015
|
|
|
901
1016
|
private func transitionSnapshotView(from webView: UIView, sourceRect: CGRect?) -> UIView {
|
|
902
1017
|
guard let sourceRect = sourceRect else {
|
|
903
|
-
return webView.snapshotView(afterScreenUpdates: false) ??
|
|
1018
|
+
return webView.snapshotView(afterScreenUpdates: false) ?? nativeNavigationSnapshotPlaceholder(for: webView)
|
|
904
1019
|
}
|
|
905
1020
|
|
|
906
1021
|
let cropRect = sourceRect.intersection(webView.bounds)
|
|
907
1022
|
guard cropRect.width > 0, cropRect.height > 0 else {
|
|
908
|
-
return webView.snapshotView(afterScreenUpdates: false) ??
|
|
1023
|
+
return webView.snapshotView(afterScreenUpdates: false) ?? nativeNavigationSnapshotPlaceholder(for: webView)
|
|
909
1024
|
}
|
|
910
1025
|
|
|
911
1026
|
let renderer = UIGraphicsImageRenderer(bounds: webView.bounds)
|
|
@@ -921,7 +1036,7 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
921
1036
|
).integral
|
|
922
1037
|
|
|
923
1038
|
guard let croppedImage = image.cgImage?.cropping(to: scaledCropRect) else {
|
|
924
|
-
return webView.snapshotView(afterScreenUpdates: false) ??
|
|
1039
|
+
return webView.snapshotView(afterScreenUpdates: false) ?? nativeNavigationSnapshotPlaceholder(for: webView)
|
|
925
1040
|
}
|
|
926
1041
|
|
|
927
1042
|
let imageView = UIImageView(image: UIImage(cgImage: croppedImage, scale: scale, orientation: image.imageOrientation))
|
|
@@ -1142,6 +1257,7 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
1142
1257
|
if let navContainer = navContainer {
|
|
1143
1258
|
bridge?.viewController?.view.bringSubviewToFront(navContainer)
|
|
1144
1259
|
}
|
|
1260
|
+
bringLiftedWebViewOverlaysToFront()
|
|
1145
1261
|
return
|
|
1146
1262
|
}
|
|
1147
1263
|
|
|
@@ -1367,22 +1483,82 @@ private final class NativeNavigationBar: UINavigationBar {
|
|
|
1367
1483
|
}
|
|
1368
1484
|
}
|
|
1369
1485
|
|
|
1370
|
-
|
|
1486
|
+
final class NativeNavigationWeakView {
|
|
1487
|
+
weak var value: UIView?
|
|
1488
|
+
|
|
1489
|
+
init(_ value: UIView) {
|
|
1490
|
+
self.value = value
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
func nativeNavigationLiftWebViewOverlaySubviews(
|
|
1495
|
+
from webView: UIView,
|
|
1496
|
+
to container: UIView,
|
|
1497
|
+
tracking liftedOverlays: inout [NativeNavigationWeakView],
|
|
1498
|
+
excluding excludedViews: [UIView?] = []
|
|
1499
|
+
) {
|
|
1500
|
+
webView.subviews
|
|
1501
|
+
.filter { nativeNavigationShouldLiftWebViewOverlay($0, excluding: excludedViews) }
|
|
1502
|
+
.forEach { overlay in
|
|
1503
|
+
let frame = overlay.convert(overlay.bounds, to: container)
|
|
1504
|
+
let hadParentConstraints = nativeNavigationDeactivateParentConstraints(in: webView, involving: overlay)
|
|
1505
|
+
overlay.removeFromSuperview()
|
|
1506
|
+
overlay.frame = frame
|
|
1507
|
+
if hadParentConstraints {
|
|
1508
|
+
overlay.translatesAutoresizingMaskIntoConstraints = true
|
|
1509
|
+
}
|
|
1510
|
+
overlay.autoresizingMask = overlay.autoresizingMask.isEmpty
|
|
1511
|
+
? [.flexibleWidth, .flexibleHeight]
|
|
1512
|
+
: overlay.autoresizingMask
|
|
1513
|
+
container.addSubview(overlay)
|
|
1514
|
+
liftedOverlays.append(NativeNavigationWeakView(overlay))
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
liftedOverlays = liftedOverlays.filter { $0.value != nil }
|
|
1518
|
+
liftedOverlays
|
|
1519
|
+
.compactMap(\.value)
|
|
1520
|
+
.filter { $0.superview === container }
|
|
1521
|
+
.forEach { container.bringSubviewToFront($0) }
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
func nativeNavigationShouldLiftWebViewOverlay(_ view: UIView, excluding excludedViews: [UIView?] = []) -> Bool {
|
|
1525
|
+
if excludedViews.contains(where: { $0 === view }) {
|
|
1526
|
+
return false
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
if view is UIScrollView {
|
|
1530
|
+
return false
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
let className = NSStringFromClass(type(of: view))
|
|
1534
|
+
return !className.contains("WK")
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
private func nativeNavigationDeactivateParentConstraints(in parent: UIView, involving view: UIView) -> Bool {
|
|
1538
|
+
let constraints = parent.constraints.filter { constraint in
|
|
1539
|
+
constraint.firstItem === view || constraint.secondItem === view
|
|
1540
|
+
}
|
|
1541
|
+
NSLayoutConstraint.deactivate(constraints)
|
|
1542
|
+
return !constraints.isEmpty
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
final class NativeNavigationTabController: UITabBarController {
|
|
1371
1546
|
override func viewDidLoad() {
|
|
1372
1547
|
super.viewDidLoad()
|
|
1373
|
-
view.backgroundColor = .
|
|
1374
|
-
view.isOpaque =
|
|
1548
|
+
view.backgroundColor = .systemBackground
|
|
1549
|
+
view.isOpaque = true
|
|
1375
1550
|
tabBar.isTranslucent = true
|
|
1376
1551
|
}
|
|
1377
1552
|
}
|
|
1378
1553
|
|
|
1379
|
-
|
|
1554
|
+
final class NativeNavigationTabContentController: UIViewController {
|
|
1380
1555
|
private weak var hostedWebView: UIView?
|
|
1556
|
+
private var snapshotPlaceholder: UIView?
|
|
1381
1557
|
|
|
1382
1558
|
override func loadView() {
|
|
1383
1559
|
let view = UIView()
|
|
1384
|
-
view.backgroundColor = .
|
|
1385
|
-
view.isOpaque =
|
|
1560
|
+
view.backgroundColor = .systemBackground
|
|
1561
|
+
view.isOpaque = true
|
|
1386
1562
|
self.view = view
|
|
1387
1563
|
}
|
|
1388
1564
|
|
|
@@ -1395,26 +1571,58 @@ private final class NativeNavigationTabContentController: UIViewController {
|
|
|
1395
1571
|
hostedWebView?.frame = view.bounds
|
|
1396
1572
|
}
|
|
1397
1573
|
|
|
1398
|
-
func clearHostedWebView(ifMatching webView: UIView? = nil) {
|
|
1574
|
+
func clearHostedWebView(ifMatching webView: UIView? = nil, preservingSnapshot: Bool = false) {
|
|
1399
1575
|
guard webView == nil || hostedWebView === webView else {
|
|
1400
1576
|
return
|
|
1401
1577
|
}
|
|
1578
|
+
|
|
1579
|
+
if preservingSnapshot, let hostedWebView = hostedWebView, hostedWebView.superview === view {
|
|
1580
|
+
let placeholder = hostedWebView.snapshotView(afterScreenUpdates: false) ?? nativeNavigationSnapshotPlaceholder(for: hostedWebView)
|
|
1581
|
+
placeholder.frame = hostedWebView.frame
|
|
1582
|
+
placeholder.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
1583
|
+
snapshotPlaceholder?.removeFromSuperview()
|
|
1584
|
+
view.insertSubview(placeholder, belowSubview: hostedWebView)
|
|
1585
|
+
snapshotPlaceholder = placeholder
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1402
1588
|
hostedWebView = nil
|
|
1403
1589
|
}
|
|
1404
1590
|
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1591
|
+
@discardableResult
|
|
1592
|
+
func host(webView: UIView) -> Bool {
|
|
1593
|
+
guard view !== webView, !view.isDescendant(of: webView) else {
|
|
1594
|
+
hostedWebView = nil
|
|
1595
|
+
return false
|
|
1408
1596
|
}
|
|
1597
|
+
|
|
1598
|
+
snapshotPlaceholder?.removeFromSuperview()
|
|
1599
|
+
snapshotPlaceholder = nil
|
|
1600
|
+
hostedWebView = webView
|
|
1409
1601
|
if webView.superview !== view {
|
|
1410
1602
|
webView.removeFromSuperview()
|
|
1411
1603
|
view.addSubview(webView)
|
|
1412
1604
|
}
|
|
1413
1605
|
webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
1414
1606
|
webView.frame = view.bounds
|
|
1607
|
+
return true
|
|
1415
1608
|
}
|
|
1416
1609
|
}
|
|
1417
1610
|
|
|
1611
|
+
private func nativeNavigationFallbackBackground(for view: UIView) -> UIColor {
|
|
1612
|
+
if let color = view.backgroundColor,
|
|
1613
|
+
color.cgColor.alpha > 0 {
|
|
1614
|
+
return color
|
|
1615
|
+
}
|
|
1616
|
+
return .systemBackground
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
private func nativeNavigationSnapshotPlaceholder(for view: UIView) -> UIView {
|
|
1620
|
+
let placeholder = UIView(frame: view.frame)
|
|
1621
|
+
placeholder.backgroundColor = nativeNavigationFallbackBackground(for: view)
|
|
1622
|
+
placeholder.isOpaque = true
|
|
1623
|
+
return placeholder
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1418
1626
|
private final class SVGIconRenderer: NSObject, XMLParserDelegate {
|
|
1419
1627
|
private let context: CGContext
|
|
1420
1628
|
private var styleStack = [SVGRenderStyle()]
|
|
@@ -1,19 +1,92 @@
|
|
|
1
1
|
import XCTest
|
|
2
|
+
import UIKit
|
|
2
3
|
@testable import NativeNavigationPlugin
|
|
3
4
|
|
|
4
5
|
class NativeNavigationTests: XCTestCase {
|
|
5
|
-
func testEcho() {
|
|
6
|
-
let implementation = NativeNavigation()
|
|
7
|
-
let value = "Hello, World!"
|
|
8
|
-
let result = implementation.echo(value)
|
|
9
|
-
|
|
10
|
-
XCTAssertEqual(value, result)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
6
|
func testGetPluginVersion() {
|
|
14
7
|
let implementation = NativeNavigation()
|
|
15
8
|
let result = implementation.getPluginVersion()
|
|
16
9
|
|
|
17
10
|
XCTAssertEqual("native", result)
|
|
18
11
|
}
|
|
12
|
+
|
|
13
|
+
func testTabContentControllerHostsWebView() {
|
|
14
|
+
let webView = UIView()
|
|
15
|
+
let originalContainer = UIView()
|
|
16
|
+
let controller = NativeNavigationTabContentController()
|
|
17
|
+
_ = controller.view
|
|
18
|
+
|
|
19
|
+
originalContainer.addSubview(webView)
|
|
20
|
+
|
|
21
|
+
XCTAssertTrue(controller.host(webView: webView))
|
|
22
|
+
XCTAssertEqual(webView.superview, controller.view)
|
|
23
|
+
XCTAssertEqual(webView.frame, controller.view.bounds)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
func testTabContentControllerKeepsSnapshotPlaceholderWhenWebViewMoves() {
|
|
27
|
+
let webView = UIView()
|
|
28
|
+
let firstController = NativeNavigationTabContentController()
|
|
29
|
+
let secondController = NativeNavigationTabContentController()
|
|
30
|
+
_ = firstController.view
|
|
31
|
+
_ = secondController.view
|
|
32
|
+
|
|
33
|
+
firstController.view.frame = CGRect(x: 0, y: 0, width: 320, height: 480)
|
|
34
|
+
secondController.view.frame = CGRect(x: 0, y: 0, width: 320, height: 480)
|
|
35
|
+
webView.backgroundColor = .systemBackground
|
|
36
|
+
|
|
37
|
+
XCTAssertTrue(firstController.host(webView: webView))
|
|
38
|
+
XCTAssertEqual(firstController.view.subviews.count, 1)
|
|
39
|
+
|
|
40
|
+
firstController.clearHostedWebView(ifMatching: webView, preservingSnapshot: true)
|
|
41
|
+
XCTAssertEqual(firstController.view.subviews.count, 2)
|
|
42
|
+
|
|
43
|
+
XCTAssertTrue(secondController.host(webView: webView))
|
|
44
|
+
XCTAssertEqual(webView.superview, secondController.view)
|
|
45
|
+
XCTAssertEqual(firstController.view.subviews.count, 1)
|
|
46
|
+
XCTAssertFalse(firstController.view.subviews.contains(webView))
|
|
47
|
+
|
|
48
|
+
XCTAssertTrue(firstController.host(webView: webView))
|
|
49
|
+
XCTAssertEqual(webView.superview, firstController.view)
|
|
50
|
+
XCTAssertEqual(firstController.view.subviews.count, 1)
|
|
51
|
+
XCTAssertTrue(firstController.view.subviews.first === webView)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
func testLiftWebViewOverlaySubviewsMovesSplashOverlayAboveContainerContent() {
|
|
55
|
+
let webView = UIView(frame: CGRect(x: 0, y: 0, width: 320, height: 480))
|
|
56
|
+
let container = UIView(frame: webView.frame)
|
|
57
|
+
let tabControllerView = UIView(frame: webView.frame)
|
|
58
|
+
let scrollView = UIScrollView(frame: webView.bounds)
|
|
59
|
+
let splashOverlay = UIView(frame: webView.bounds)
|
|
60
|
+
var liftedOverlays: [NativeNavigationWeakView] = []
|
|
61
|
+
|
|
62
|
+
container.addSubview(webView)
|
|
63
|
+
container.addSubview(tabControllerView)
|
|
64
|
+
webView.addSubview(scrollView)
|
|
65
|
+
webView.addSubview(splashOverlay)
|
|
66
|
+
|
|
67
|
+
nativeNavigationLiftWebViewOverlaySubviews(
|
|
68
|
+
from: webView,
|
|
69
|
+
to: container,
|
|
70
|
+
tracking: &liftedOverlays,
|
|
71
|
+
excluding: [tabControllerView]
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
XCTAssertEqual(scrollView.superview, webView)
|
|
75
|
+
XCTAssertEqual(splashOverlay.superview, container)
|
|
76
|
+
XCTAssertTrue(container.subviews.last === splashOverlay)
|
|
77
|
+
XCTAssertEqual(liftedOverlays.count, 1)
|
|
78
|
+
XCTAssertTrue(liftedOverlays.first?.value === splashOverlay)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
func testTabContentControllerRejectsLayerCycle() {
|
|
82
|
+
let webView = UIView()
|
|
83
|
+
let controller = NativeNavigationTabContentController()
|
|
84
|
+
_ = controller.view
|
|
85
|
+
|
|
86
|
+
webView.addSubview(controller.view)
|
|
87
|
+
|
|
88
|
+
XCTAssertFalse(controller.host(webView: webView))
|
|
89
|
+
XCTAssertNil(webView.superview)
|
|
90
|
+
XCTAssertEqual(controller.view.superview, webView)
|
|
91
|
+
}
|
|
19
92
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capgo/capacitor-native-navigation",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.17",
|
|
4
4
|
"description": "Capacitor plugin for native navbar, tabbar, and route transition chrome over a WebView.",
|
|
5
5
|
"main": "dist/plugin.cjs.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
"url": "https://github.com/Cap-go/capacitor-native-navigation/issues"
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://capgo.app/docs/plugins/native-navigation/",
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=22.0.0"
|
|
31
|
+
},
|
|
29
32
|
"keywords": [
|
|
30
33
|
"capacitor",
|
|
31
34
|
"native-navigation",
|