@capgo/capacitor-native-navigation 8.0.13 → 8.0.15-beta.pr12.18.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/{CapgoNativeNavigation.podspec → CapgoCapacitorNativeNavigation.podspec} +1 -1
- package/Package.swift +2 -2
- package/ios/Sources/NativeNavigationPlugin/NativeNavigationPlugin.swift +97 -7
- package/ios/Tests/NativeNavigationPluginTests/NativeNavigationTests.swift +26 -8
- package/package.json +3 -3
|
@@ -3,7 +3,7 @@ require 'json'
|
|
|
3
3
|
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
4
4
|
|
|
5
5
|
Pod::Spec.new do |s|
|
|
6
|
-
s.name = '
|
|
6
|
+
s.name = 'CapgoCapacitorNativeNavigation'
|
|
7
7
|
s.version = package['version']
|
|
8
8
|
s.summary = package['description']
|
|
9
9
|
s.license = package['license']
|
package/Package.swift
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
import PackageDescription
|
|
3
3
|
|
|
4
4
|
let package = Package(
|
|
5
|
-
name: "
|
|
5
|
+
name: "CapgoCapacitorNativeNavigation",
|
|
6
6
|
platforms: [.iOS(.v15)],
|
|
7
7
|
products: [
|
|
8
8
|
.library(
|
|
9
|
-
name: "
|
|
9
|
+
name: "CapgoCapacitorNativeNavigation",
|
|
10
10
|
targets: ["NativeNavigationPlugin"])
|
|
11
11
|
],
|
|
12
12
|
dependencies: [
|
|
@@ -44,6 +44,7 @@ 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?
|
|
@@ -552,8 +553,9 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
552
553
|
controller.view.isHidden = !tabbarVisible
|
|
553
554
|
|
|
554
555
|
if let parent = bridge?.viewController {
|
|
556
|
+
let containerView = systemTabHostingContainerView(in: parent)
|
|
555
557
|
parent.addChild(controller)
|
|
556
|
-
|
|
558
|
+
insertSystemTabControllerView(controller.view, in: containerView)
|
|
557
559
|
controller.didMove(toParent: parent)
|
|
558
560
|
}
|
|
559
561
|
|
|
@@ -563,6 +565,49 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
563
565
|
return controller.tabBar
|
|
564
566
|
}
|
|
565
567
|
|
|
568
|
+
private func systemTabHostingContainerView(in parent: UIViewController) -> UIView {
|
|
569
|
+
if let systemTabRootContainer = systemTabRootContainer {
|
|
570
|
+
return systemTabRootContainer
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
guard let webView = webView,
|
|
574
|
+
parent.view === webView else {
|
|
575
|
+
return parent.view
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
let previousSuperview = webView.superview
|
|
579
|
+
let previousIndex = previousSuperview?.subviews.firstIndex(of: webView)
|
|
580
|
+
let previousFrame = webView.frame
|
|
581
|
+
let previousAutoresizingMask = webView.autoresizingMask
|
|
582
|
+
let container = UIView(frame: previousFrame)
|
|
583
|
+
container.backgroundColor = .clear
|
|
584
|
+
container.isOpaque = false
|
|
585
|
+
container.autoresizingMask = previousAutoresizingMask.isEmpty ? [.flexibleWidth, .flexibleHeight] : previousAutoresizingMask
|
|
586
|
+
|
|
587
|
+
if let previousSuperview = previousSuperview {
|
|
588
|
+
previousSuperview.insertSubview(container, at: min(previousIndex ?? previousSuperview.subviews.count, previousSuperview.subviews.count))
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
parent.view = container
|
|
592
|
+
container.addSubview(webView)
|
|
593
|
+
webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
594
|
+
webView.frame = container.bounds
|
|
595
|
+
moveNativeChrome(from: webView, to: container)
|
|
596
|
+
|
|
597
|
+
systemTabRootContainer = container
|
|
598
|
+
originalWebViewSuperview = container
|
|
599
|
+
originalWebViewIndex = 0
|
|
600
|
+
originalWebViewAutoresizingMask = webView.autoresizingMask
|
|
601
|
+
return container
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
private func moveNativeChrome(from webView: UIView, to container: UIView) {
|
|
605
|
+
if let navContainer = navContainer,
|
|
606
|
+
navContainer.superview === webView {
|
|
607
|
+
container.addSubview(navContainer)
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
566
611
|
private func applySystemTabBarItems(_ items: [UITabBarItem], selectedIndex: Int?, animated: Bool) {
|
|
567
612
|
guard let tabBarController = tabBarController else {
|
|
568
613
|
return
|
|
@@ -633,6 +678,43 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
633
678
|
originalWebViewAutoresizingMask = webView.autoresizingMask
|
|
634
679
|
}
|
|
635
680
|
|
|
681
|
+
private func insertSystemTabControllerView(_ controllerView: UIView, in parentView: UIView) {
|
|
682
|
+
guard let webView = webView else {
|
|
683
|
+
parentView.addSubview(controllerView)
|
|
684
|
+
return
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
captureOriginalWebViewPlacementIfNeeded(webView)
|
|
688
|
+
let insertionIndex = systemTabControllerInsertionIndex(in: parentView, for: webView)
|
|
689
|
+
parentView.insertSubview(controllerView, at: insertionIndex)
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
private func systemTabControllerInsertionIndex(in parentView: UIView, for webView: UIView) -> Int {
|
|
693
|
+
if let directChild = directChild(of: parentView, containing: webView),
|
|
694
|
+
let index = parentView.subviews.firstIndex(of: directChild) {
|
|
695
|
+
return min(index, parentView.subviews.count)
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
if let originalWebViewSuperview = originalWebViewSuperview,
|
|
699
|
+
originalWebViewSuperview === parentView {
|
|
700
|
+
return min(originalWebViewIndex ?? parentView.subviews.count, parentView.subviews.count)
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
return parentView.subviews.count
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
private func directChild(of ancestor: UIView, containing descendant: UIView) -> UIView? {
|
|
707
|
+
var current: UIView? = descendant
|
|
708
|
+
while let view = current, let superview = view.superview {
|
|
709
|
+
if superview === ancestor {
|
|
710
|
+
return view
|
|
711
|
+
}
|
|
712
|
+
current = superview
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
return nil
|
|
716
|
+
}
|
|
717
|
+
|
|
636
718
|
private func hostWebViewInSelectedSystemTab() {
|
|
637
719
|
guard usesSystemLiquidGlass,
|
|
638
720
|
let webView = webView,
|
|
@@ -642,7 +724,10 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarContro
|
|
|
642
724
|
|
|
643
725
|
captureOriginalWebViewPlacementIfNeeded(webView)
|
|
644
726
|
clearHostedWebViews(matching: webView, except: selectedController)
|
|
645
|
-
selectedController.host(webView: webView)
|
|
727
|
+
guard selectedController.host(webView: webView) else {
|
|
728
|
+
isWebViewHostedInSystemTabController = false
|
|
729
|
+
return
|
|
730
|
+
}
|
|
646
731
|
clearHostedWebViews(matching: webView, except: selectedController)
|
|
647
732
|
isWebViewHostedInSystemTabController = true
|
|
648
733
|
}
|
|
@@ -1330,7 +1415,7 @@ private final class NativeNavigationBar: UINavigationBar {
|
|
|
1330
1415
|
}
|
|
1331
1416
|
}
|
|
1332
1417
|
|
|
1333
|
-
|
|
1418
|
+
final class NativeNavigationTabController: UITabBarController {
|
|
1334
1419
|
override func viewDidLoad() {
|
|
1335
1420
|
super.viewDidLoad()
|
|
1336
1421
|
view.backgroundColor = .clear
|
|
@@ -1339,7 +1424,7 @@ private final class NativeNavigationTabController: UITabBarController {
|
|
|
1339
1424
|
}
|
|
1340
1425
|
}
|
|
1341
1426
|
|
|
1342
|
-
|
|
1427
|
+
final class NativeNavigationTabContentController: UIViewController {
|
|
1343
1428
|
private weak var hostedWebView: UIView?
|
|
1344
1429
|
|
|
1345
1430
|
override func loadView() {
|
|
@@ -1365,16 +1450,21 @@ private final class NativeNavigationTabContentController: UIViewController {
|
|
|
1365
1450
|
hostedWebView = nil
|
|
1366
1451
|
}
|
|
1367
1452
|
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1453
|
+
@discardableResult
|
|
1454
|
+
func host(webView: UIView) -> Bool {
|
|
1455
|
+
guard view !== webView, !view.isDescendant(of: webView) else {
|
|
1456
|
+
hostedWebView = nil
|
|
1457
|
+
return false
|
|
1371
1458
|
}
|
|
1459
|
+
|
|
1460
|
+
hostedWebView = webView
|
|
1372
1461
|
if webView.superview !== view {
|
|
1373
1462
|
webView.removeFromSuperview()
|
|
1374
1463
|
view.addSubview(webView)
|
|
1375
1464
|
}
|
|
1376
1465
|
webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
1377
1466
|
webView.frame = view.bounds
|
|
1467
|
+
return true
|
|
1378
1468
|
}
|
|
1379
1469
|
}
|
|
1380
1470
|
|
|
@@ -1,19 +1,37 @@
|
|
|
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 testTabContentControllerRejectsLayerCycle() {
|
|
27
|
+
let webView = UIView()
|
|
28
|
+
let controller = NativeNavigationTabContentController()
|
|
29
|
+
_ = controller.view
|
|
30
|
+
|
|
31
|
+
webView.addSubview(controller.view)
|
|
32
|
+
|
|
33
|
+
XCTAssertFalse(controller.host(webView: webView))
|
|
34
|
+
XCTAssertNil(webView.superview)
|
|
35
|
+
XCTAssertEqual(controller.view.superview, webView)
|
|
36
|
+
}
|
|
19
37
|
}
|
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.15-beta.pr12.18.1",
|
|
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",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"ios/Sources",
|
|
15
15
|
"ios/Tests",
|
|
16
16
|
"Package.swift",
|
|
17
|
-
"
|
|
17
|
+
"CapgoCapacitorNativeNavigation.podspec"
|
|
18
18
|
],
|
|
19
19
|
"author": "Martin Donadieu <martin@capgo.app>",
|
|
20
20
|
"license": "MPL-2.0",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
],
|
|
36
36
|
"scripts": {
|
|
37
37
|
"verify": "bun run verify:ios && bun run verify:android && bun run verify:web",
|
|
38
|
-
"verify:ios": "xcodebuild -scheme
|
|
38
|
+
"verify:ios": "xcodebuild -scheme CapgoCapacitorNativeNavigation -destination generic/platform=iOS",
|
|
39
39
|
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
|
40
40
|
"verify:web": "bun run build",
|
|
41
41
|
"lint": "bun run eslint && bun run prettier -- --check && bun run swiftlint -- lint",
|