@capgo/capacitor-native-navigation 8.0.12 → 8.0.14
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,6 +44,10 @@ 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 originalWebViewSuperview: UIView?
|
|
48
|
+
private var originalWebViewIndex: Int?
|
|
49
|
+
private var originalWebViewAutoresizingMask: UIView.AutoresizingMask?
|
|
50
|
+
private var isWebViewHostedInSystemTabController = false
|
|
47
51
|
private var navbarHeight: CGFloat = 44
|
|
48
52
|
private var tabbarHeight: CGFloat = 64
|
|
49
53
|
private let floatingTabbarHorizontalMargin: CGFloat = 24
|
|
@@ -96,6 +100,7 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
96
100
|
if !self.isEnabled {
|
|
97
101
|
self.navContainer?.isHidden = true
|
|
98
102
|
self.tabContainer?.isHidden = true
|
|
103
|
+
self.restoreWebViewFromSystemTabController()
|
|
99
104
|
self.tabBarController?.view.isHidden = true
|
|
100
105
|
self.tabBar?.isHidden = true
|
|
101
106
|
}
|
|
@@ -170,9 +175,7 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
170
175
|
self.tabbarVisible = !hidden
|
|
171
176
|
|
|
172
177
|
guard !hidden else {
|
|
173
|
-
self.
|
|
174
|
-
self.tabBarController?.view.isHidden = true
|
|
175
|
-
self.tabBar?.isHidden = true
|
|
178
|
+
self.hideTabBarChrome()
|
|
176
179
|
self.updateInsetsAndNotify()
|
|
177
180
|
call.resolve(self.insetsResult())
|
|
178
181
|
return
|
|
@@ -204,9 +207,7 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
204
207
|
}
|
|
205
208
|
|
|
206
209
|
self.applyTabBarAppearance(tabBar: tabBar, options: call)
|
|
207
|
-
self.
|
|
208
|
-
self.tabBarController?.view.isHidden = false
|
|
209
|
-
tabBar.isHidden = false
|
|
210
|
+
self.showTabBarChrome(tabBar)
|
|
210
211
|
self.layoutChrome()
|
|
211
212
|
self.updateInsetsAndNotify()
|
|
212
213
|
call.resolve(self.insetsResult())
|
|
@@ -215,7 +216,8 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
215
216
|
|
|
216
217
|
@objc func beginTransition(_ call: CAPPluginCall) {
|
|
217
218
|
DispatchQueue.main.async {
|
|
218
|
-
guard let webView = self.webView,
|
|
219
|
+
guard let webView = self.webView,
|
|
220
|
+
let transitionContainer = webView.superview else {
|
|
219
221
|
call.reject("WebView unavailable")
|
|
220
222
|
return
|
|
221
223
|
}
|
|
@@ -224,7 +226,7 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
224
226
|
let direction = call.getString("direction") ?? "forward"
|
|
225
227
|
let durationMs = Int((call.getDouble("duration") ?? self.defaultTransitionDuration * 1_000).rounded())
|
|
226
228
|
let zoomSourceRect = direction == "zoom" ? self.transitionRect(call.getObject("sourceRect")) : nil
|
|
227
|
-
let zoomSourceFrame = zoomSourceRect.map { self.
|
|
229
|
+
let zoomSourceFrame = zoomSourceRect.map { self.transitionFrame(for: $0, webView: webView) }
|
|
228
230
|
let cornerRadius = CGFloat(call.getDouble("cornerRadius") ?? 0)
|
|
229
231
|
|
|
230
232
|
self.transitionSnapshot?.removeFromSuperview()
|
|
@@ -233,7 +235,7 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
233
235
|
snapshot.autoresizingMask = zoomSourceFrame == nil ? [.flexibleWidth, .flexibleHeight] : []
|
|
234
236
|
snapshot.layer.cornerRadius = cornerRadius
|
|
235
237
|
snapshot.clipsToBounds = cornerRadius > 0
|
|
236
|
-
|
|
238
|
+
transitionContainer.insertSubview(snapshot, aboveSubview: webView)
|
|
237
239
|
self.bringChromeToFront()
|
|
238
240
|
self.transitionSnapshot = snapshot
|
|
239
241
|
self.activeTransitionId = transitionId
|
|
@@ -274,8 +276,8 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
274
276
|
let targetRect = self.transitionRect(call.getObject("targetRect"))
|
|
275
277
|
self.finishZoomTransition(NativeNavigationZoomTransitionContext(
|
|
276
278
|
transition: transition,
|
|
277
|
-
sourceFrame: sourceRect.map { self.
|
|
278
|
-
targetFrame: targetRect.map { self.
|
|
279
|
+
sourceFrame: sourceRect.map { self.transitionFrame(for: $0, webView: webView) },
|
|
280
|
+
targetFrame: targetRect.map { self.transitionFrame(for: $0, webView: webView) },
|
|
279
281
|
cornerRadius: CGFloat(call.getDouble("cornerRadius") ?? Double(self.activeZoomCornerRadius))
|
|
280
282
|
))
|
|
281
283
|
return
|
|
@@ -437,9 +439,11 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
437
439
|
|
|
438
440
|
public func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
|
|
439
441
|
guard !suppressTabSelectEvent else {
|
|
442
|
+
hostWebViewInSelectedSystemTab()
|
|
440
443
|
return
|
|
441
444
|
}
|
|
442
445
|
let index = tabBarController.viewControllers?.firstIndex(of: viewController) ?? viewController.tabBarItem.tag
|
|
446
|
+
hostWebViewInSelectedSystemTab()
|
|
443
447
|
notifyTabSelect(index: index)
|
|
444
448
|
}
|
|
445
449
|
|
|
@@ -538,6 +542,7 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
538
542
|
|
|
539
543
|
private func ensureSystemTabBar() -> UITabBar {
|
|
540
544
|
if let tabBarController = tabBarController {
|
|
545
|
+
hostWebViewInSelectedSystemTab()
|
|
541
546
|
return tabBarController.tabBar
|
|
542
547
|
}
|
|
543
548
|
|
|
@@ -548,12 +553,13 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
548
553
|
|
|
549
554
|
if let parent = bridge?.viewController {
|
|
550
555
|
parent.addChild(controller)
|
|
551
|
-
|
|
556
|
+
insertSystemTabControllerView(controller.view, in: parent.view)
|
|
552
557
|
controller.didMove(toParent: parent)
|
|
553
558
|
}
|
|
554
559
|
|
|
555
560
|
self.tabBarController = controller
|
|
556
561
|
self.tabBar = controller.tabBar
|
|
562
|
+
hostWebViewInSelectedSystemTab()
|
|
557
563
|
return controller.tabBar
|
|
558
564
|
}
|
|
559
565
|
|
|
@@ -577,11 +583,130 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
577
583
|
let index = min(max(fallbackIndex, 0), controllers.count - 1)
|
|
578
584
|
tabBarController.selectedIndex = index
|
|
579
585
|
}
|
|
586
|
+
hostWebViewInSelectedSystemTab()
|
|
580
587
|
suppressTabSelectEvent = false
|
|
581
588
|
|
|
582
589
|
tabViewControllers = controllers
|
|
583
590
|
}
|
|
584
591
|
|
|
592
|
+
private func setSystemTabBarHidden(_ hidden: Bool) {
|
|
593
|
+
guard let tabBarController = tabBarController else {
|
|
594
|
+
return
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
if #available(iOS 18.0, *) {
|
|
598
|
+
tabBarController.setTabBarHidden(hidden, animated: false)
|
|
599
|
+
} else {
|
|
600
|
+
tabBarController.tabBar.isHidden = hidden
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
private func hideTabBarChrome() {
|
|
605
|
+
if usesSystemLiquidGlass {
|
|
606
|
+
setSystemTabBarHidden(true)
|
|
607
|
+
tabBarController?.view.isHidden = false
|
|
608
|
+
hostWebViewInSelectedSystemTab()
|
|
609
|
+
} else {
|
|
610
|
+
tabContainer?.isHidden = true
|
|
611
|
+
tabBar?.isHidden = true
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
private func showTabBarChrome(_ tabBar: UITabBar) {
|
|
616
|
+
tabContainer?.isHidden = false
|
|
617
|
+
tabBarController?.view.isHidden = false
|
|
618
|
+
if usesSystemLiquidGlass {
|
|
619
|
+
setSystemTabBarHidden(false)
|
|
620
|
+
hostWebViewInSelectedSystemTab()
|
|
621
|
+
} else {
|
|
622
|
+
tabBar.isHidden = false
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
private func captureOriginalWebViewPlacementIfNeeded(_ webView: UIView) {
|
|
627
|
+
guard originalWebViewSuperview == nil, let superview = webView.superview else {
|
|
628
|
+
return
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
originalWebViewSuperview = superview
|
|
632
|
+
originalWebViewIndex = superview.subviews.firstIndex(of: webView)
|
|
633
|
+
originalWebViewAutoresizingMask = webView.autoresizingMask
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
private func insertSystemTabControllerView(_ controllerView: UIView, in parentView: UIView) {
|
|
637
|
+
guard let webView = webView else {
|
|
638
|
+
parentView.addSubview(controllerView)
|
|
639
|
+
return
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
captureOriginalWebViewPlacementIfNeeded(webView)
|
|
643
|
+
let insertionIndex = systemTabControllerInsertionIndex(in: parentView, for: webView)
|
|
644
|
+
parentView.insertSubview(controllerView, at: insertionIndex)
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
private func systemTabControllerInsertionIndex(in parentView: UIView, for webView: UIView) -> Int {
|
|
648
|
+
if let directChild = directChild(of: parentView, containing: webView),
|
|
649
|
+
let index = parentView.subviews.firstIndex(of: directChild) {
|
|
650
|
+
return min(index, parentView.subviews.count)
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
if let originalWebViewSuperview = originalWebViewSuperview,
|
|
654
|
+
originalWebViewSuperview === parentView {
|
|
655
|
+
return min(originalWebViewIndex ?? parentView.subviews.count, parentView.subviews.count)
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
return parentView.subviews.count
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
private func directChild(of ancestor: UIView, containing descendant: UIView) -> UIView? {
|
|
662
|
+
var current: UIView? = descendant
|
|
663
|
+
while let view = current, let superview = view.superview {
|
|
664
|
+
if superview === ancestor {
|
|
665
|
+
return view
|
|
666
|
+
}
|
|
667
|
+
current = superview
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
return nil
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
private func hostWebViewInSelectedSystemTab() {
|
|
674
|
+
guard usesSystemLiquidGlass,
|
|
675
|
+
let webView = webView,
|
|
676
|
+
let selectedController = tabBarController?.selectedViewController as? NativeNavigationTabContentController else {
|
|
677
|
+
return
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
captureOriginalWebViewPlacementIfNeeded(webView)
|
|
681
|
+
clearHostedWebViews(matching: webView, except: selectedController)
|
|
682
|
+
selectedController.host(webView: webView)
|
|
683
|
+
clearHostedWebViews(matching: webView, except: selectedController)
|
|
684
|
+
isWebViewHostedInSystemTabController = true
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
private func restoreWebViewFromSystemTabController() {
|
|
688
|
+
guard isWebViewHostedInSystemTabController,
|
|
689
|
+
let webView = webView,
|
|
690
|
+
let targetSuperview = originalWebViewSuperview ?? bridge?.viewController?.view else {
|
|
691
|
+
return
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
let insertionIndex = min(originalWebViewIndex ?? targetSuperview.subviews.count, targetSuperview.subviews.count)
|
|
695
|
+
clearHostedWebViews(matching: webView)
|
|
696
|
+
webView.removeFromSuperview()
|
|
697
|
+
targetSuperview.insertSubview(webView, at: insertionIndex)
|
|
698
|
+
webView.autoresizingMask = originalWebViewAutoresizingMask ?? [.flexibleWidth, .flexibleHeight]
|
|
699
|
+
webView.frame = targetSuperview.bounds
|
|
700
|
+
isWebViewHostedInSystemTabController = false
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
private func clearHostedWebViews(matching webView: UIView, except owner: NativeNavigationTabContentController? = nil) {
|
|
704
|
+
tabViewControllers
|
|
705
|
+
.compactMap { $0 as? NativeNavigationTabContentController }
|
|
706
|
+
.filter { $0 !== owner }
|
|
707
|
+
.forEach { $0.clearHostedWebView(ifMatching: webView) }
|
|
708
|
+
}
|
|
709
|
+
|
|
585
710
|
private func makeBarButtonItems(_ rawItems: [[String: Any]], placement: String) -> [UIBarButtonItem] {
|
|
586
711
|
return rawItems.map { rawItem in
|
|
587
712
|
let id = rawItem["id"] as? String ?? UUID().uuidString
|
|
@@ -761,13 +886,16 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
761
886
|
)
|
|
762
887
|
}
|
|
763
888
|
|
|
764
|
-
private func
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
889
|
+
private func transitionFrame(for viewportRect: CGRect, webView: UIView) -> CGRect {
|
|
890
|
+
guard let transitionContainer = webView.superview else {
|
|
891
|
+
return CGRect(
|
|
892
|
+
x: webView.frame.minX + viewportRect.minX,
|
|
893
|
+
y: webView.frame.minY + viewportRect.minY,
|
|
894
|
+
width: viewportRect.width,
|
|
895
|
+
height: viewportRect.height
|
|
896
|
+
)
|
|
897
|
+
}
|
|
898
|
+
return webView.convert(viewportRect, to: transitionContainer)
|
|
771
899
|
}
|
|
772
900
|
|
|
773
901
|
private func transitionSnapshotView(from webView: UIView, sourceRect: CGRect?) -> UIView {
|
|
@@ -1010,6 +1138,13 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
1010
1138
|
}
|
|
1011
1139
|
|
|
1012
1140
|
private func bringChromeToFront() {
|
|
1141
|
+
if usesSystemLiquidGlass {
|
|
1142
|
+
if let navContainer = navContainer {
|
|
1143
|
+
bridge?.viewController?.view.bringSubviewToFront(navContainer)
|
|
1144
|
+
}
|
|
1145
|
+
return
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1013
1148
|
if let navContainer = navContainer {
|
|
1014
1149
|
bridge?.viewController?.view.bringSubviewToFront(navContainer)
|
|
1015
1150
|
}
|
|
@@ -1233,41 +1368,51 @@ private final class NativeNavigationBar: UINavigationBar {
|
|
|
1233
1368
|
}
|
|
1234
1369
|
|
|
1235
1370
|
private final class NativeNavigationTabController: UITabBarController {
|
|
1236
|
-
override func loadView() {
|
|
1237
|
-
let view = NativeNavigationTabControllerView()
|
|
1238
|
-
view.backgroundColor = .clear
|
|
1239
|
-
view.isOpaque = false
|
|
1240
|
-
self.view = view
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
1371
|
override func viewDidLoad() {
|
|
1244
1372
|
super.viewDidLoad()
|
|
1245
1373
|
view.backgroundColor = .clear
|
|
1246
1374
|
view.isOpaque = false
|
|
1247
1375
|
tabBar.isTranslucent = true
|
|
1248
|
-
(view as? NativeNavigationTabControllerView)?.tabBar = tabBar
|
|
1249
|
-
}
|
|
1250
|
-
}
|
|
1251
|
-
|
|
1252
|
-
private final class NativeNavigationTabControllerView: UIView {
|
|
1253
|
-
weak var tabBar: UITabBar?
|
|
1254
|
-
|
|
1255
|
-
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
|
|
1256
|
-
guard let tabBar = tabBar, !tabBar.isHidden, tabBar.alpha > 0.01 else {
|
|
1257
|
-
return false
|
|
1258
|
-
}
|
|
1259
|
-
let tabPoint = convert(point, to: tabBar)
|
|
1260
|
-
return tabBar.point(inside: tabPoint, with: event)
|
|
1261
1376
|
}
|
|
1262
1377
|
}
|
|
1263
1378
|
|
|
1264
1379
|
private final class NativeNavigationTabContentController: UIViewController {
|
|
1380
|
+
private weak var hostedWebView: UIView?
|
|
1381
|
+
|
|
1265
1382
|
override func loadView() {
|
|
1266
1383
|
let view = UIView()
|
|
1267
1384
|
view.backgroundColor = .clear
|
|
1268
1385
|
view.isOpaque = false
|
|
1269
1386
|
self.view = view
|
|
1270
1387
|
}
|
|
1388
|
+
|
|
1389
|
+
override func viewDidLayoutSubviews() {
|
|
1390
|
+
super.viewDidLayoutSubviews()
|
|
1391
|
+
guard hostedWebView?.superview === view else {
|
|
1392
|
+
hostedWebView = nil
|
|
1393
|
+
return
|
|
1394
|
+
}
|
|
1395
|
+
hostedWebView?.frame = view.bounds
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
func clearHostedWebView(ifMatching webView: UIView? = nil) {
|
|
1399
|
+
guard webView == nil || hostedWebView === webView else {
|
|
1400
|
+
return
|
|
1401
|
+
}
|
|
1402
|
+
hostedWebView = nil
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
func host(webView: UIView) {
|
|
1406
|
+
if hostedWebView !== webView {
|
|
1407
|
+
hostedWebView = webView
|
|
1408
|
+
}
|
|
1409
|
+
if webView.superview !== view {
|
|
1410
|
+
webView.removeFromSuperview()
|
|
1411
|
+
view.addSubview(webView)
|
|
1412
|
+
}
|
|
1413
|
+
webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
1414
|
+
webView.frame = view.bounds
|
|
1415
|
+
}
|
|
1271
1416
|
}
|
|
1272
1417
|
|
|
1273
1418
|
private final class SVGIconRenderer: NSObject, XMLParserDelegate {
|
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.14",
|
|
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",
|