Skip to content

Commit 52d1bc0

Browse files
committed
Add UIKitNavigationLink for bridging UINavigationControllers to SwiftUI
1 parent 0f3ea3e commit 52d1bc0

File tree

6 files changed

+127
-69
lines changed

6 files changed

+127
-69
lines changed

JamitFoundationExample/App/Sources/SwiftUISupport/CandyButton.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,21 @@ import SwiftUISupport
66
struct CandyButton: View {
77
let action: () -> Void
88
@State private var isActive: Bool = false
9-
@EnvironmentObject var navigationCoordinator: NavigationCoordinator
109

1110
var body: some View {
1211
VStack {
13-
Button("Hit me 2") {
14-
navigationCoordinator.push(EmptyView())
12+
UIKitNavigationLink(
13+
destination: EmptyView()
14+
) {
15+
Text("Hit me 2")
16+
}
17+
18+
NavigationLink(
19+
destination: EmptyView()
20+
) {
21+
Text("Hit me 3")
1522
}
23+
1624
NavigationLink(
1725
destination: EmptyView(),
1826
isActive: $isActive

JamitFoundationExample/App/Sources/SwiftUISupport/SwiftUIIntegrationViewController.swift

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,7 @@ import UIKit
55
import SwiftUI
66
import SwiftUISupport
77

8-
protocol SwiftUIIntegrationViewControllerDelegate: AnyObject {
9-
// TODO: not yet implemented
10-
}
11-
128
final class SwiftUIIntegrationViewController: StatefulViewController<SwiftUIIntegrationViewModel> {
13-
weak var delegate: SwiftUIIntegrationViewControllerDelegate?
14-
159
@IBOutlet private var titleLabel: UILabel!
1610
@IBOutlet private var candyButtonContainer: UIView!
1711

JamitFoundationExample/JamitFoundationExample.xcodeproj/project.pbxproj

Lines changed: 58 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -62,17 +62,17 @@
6262
1EFCDA7124C5C1C600B41530 /* CollapsibleTableViewControllerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EFCDA6E24C5C1C600B41530 /* CollapsibleTableViewControllerViewModel.swift */; };
6363
1EFCDA7224C5C1C600B41530 /* CollapsibleTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EFCDA6F24C5C1C600B41530 /* CollapsibleTableViewController.swift */; };
6464
C54191302860ACF700E29C3B /* UIKitIntegrationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C541912F2860ACF700E29C3B /* UIKitIntegrationView.swift */; };
65-
C54191332860AD9C00E29C3B /* BarcodeScanner in Frameworks */ = {isa = PBXBuildFile; productRef = C54191322860AD9C00E29C3B /* BarcodeScanner */; };
66-
C54191352860AD9C00E29C3B /* CarouselView in Frameworks */ = {isa = PBXBuildFile; productRef = C54191342860AD9C00E29C3B /* CarouselView */; };
67-
C54191372860AD9C00E29C3B /* GridView in Frameworks */ = {isa = PBXBuildFile; productRef = C54191362860AD9C00E29C3B /* GridView */; };
68-
C54191392860AD9C00E29C3B /* JamitFoundation in Frameworks */ = {isa = PBXBuildFile; productRef = C54191382860AD9C00E29C3B /* JamitFoundation */; };
69-
C541913B2860AD9C00E29C3B /* Keychain in Frameworks */ = {isa = PBXBuildFile; productRef = C541913A2860AD9C00E29C3B /* Keychain */; };
70-
C541913D2860AD9C00E29C3B /* MessageView in Frameworks */ = {isa = PBXBuildFile; productRef = C541913C2860AD9C00E29C3B /* MessageView */; };
71-
C541913F2860AD9C00E29C3B /* PageView in Frameworks */ = {isa = PBXBuildFile; productRef = C541913E2860AD9C00E29C3B /* PageView */; };
72-
C54191412860AD9C00E29C3B /* SwiftUISupport in Frameworks */ = {isa = PBXBuildFile; productRef = C54191402860AD9C00E29C3B /* SwiftUISupport */; };
73-
C54191432860AD9C00E29C3B /* TimePickerView in Frameworks */ = {isa = PBXBuildFile; productRef = C54191422860AD9C00E29C3B /* TimePickerView */; };
74-
C54191452860AD9C00E29C3B /* UserDefaults in Frameworks */ = {isa = PBXBuildFile; productRef = C54191442860AD9C00E29C3B /* UserDefaults */; };
75-
C54191472860AD9C00E29C3B /* WeakCache in Frameworks */ = {isa = PBXBuildFile; productRef = C54191462860AD9C00E29C3B /* WeakCache */; };
65+
C5DAE5BE299D26EB00CC8947 /* BarcodeScanner in Frameworks */ = {isa = PBXBuildFile; productRef = C5DAE5BD299D26EB00CC8947 /* BarcodeScanner */; };
66+
C5DAE5C0299D26EB00CC8947 /* CarouselView in Frameworks */ = {isa = PBXBuildFile; productRef = C5DAE5BF299D26EB00CC8947 /* CarouselView */; };
67+
C5DAE5C2299D26EB00CC8947 /* GridView in Frameworks */ = {isa = PBXBuildFile; productRef = C5DAE5C1299D26EB00CC8947 /* GridView */; };
68+
C5DAE5C4299D26EB00CC8947 /* JamitFoundation in Frameworks */ = {isa = PBXBuildFile; productRef = C5DAE5C3299D26EB00CC8947 /* JamitFoundation */; };
69+
C5DAE5C6299D26EB00CC8947 /* Keychain in Frameworks */ = {isa = PBXBuildFile; productRef = C5DAE5C5299D26EB00CC8947 /* Keychain */; };
70+
C5DAE5C8299D26EB00CC8947 /* MessageView in Frameworks */ = {isa = PBXBuildFile; productRef = C5DAE5C7299D26EB00CC8947 /* MessageView */; };
71+
C5DAE5CA299D26EB00CC8947 /* PageView in Frameworks */ = {isa = PBXBuildFile; productRef = C5DAE5C9299D26EB00CC8947 /* PageView */; };
72+
C5DAE5CC299D26EB00CC8947 /* SwiftUISupport in Frameworks */ = {isa = PBXBuildFile; productRef = C5DAE5CB299D26EB00CC8947 /* SwiftUISupport */; };
73+
C5DAE5CE299D26EB00CC8947 /* TimePickerView in Frameworks */ = {isa = PBXBuildFile; productRef = C5DAE5CD299D26EB00CC8947 /* TimePickerView */; };
74+
C5DAE5D0299D26EB00CC8947 /* UserDefaults in Frameworks */ = {isa = PBXBuildFile; productRef = C5DAE5CF299D26EB00CC8947 /* UserDefaults */; };
75+
C5DAE5D2299D26EB00CC8947 /* WeakCache in Frameworks */ = {isa = PBXBuildFile; productRef = C5DAE5D1299D26EB00CC8947 /* WeakCache */; };
7676
C930B43328C87B220037BE9C /* SwiftUIIntegrationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C930B43228C87B220037BE9C /* SwiftUIIntegrationViewController.swift */; };
7777
C930B43528C87B2B0037BE9C /* CandyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C930B43428C87B2B0037BE9C /* CandyButton.swift */; };
7878
C930B43728C87B310037BE9C /* SwiftUIIntegrationViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C930B43628C87B310037BE9C /* SwiftUIIntegrationViewController.xib */; };
@@ -198,17 +198,17 @@
198198
isa = PBXFrameworksBuildPhase;
199199
buildActionMask = 2147483647;
200200
files = (
201-
C54191432860AD9C00E29C3B /* TimePickerView in Frameworks */,
202-
C54191332860AD9C00E29C3B /* BarcodeScanner in Frameworks */,
203-
C54191372860AD9C00E29C3B /* GridView in Frameworks */,
204-
C54191352860AD9C00E29C3B /* CarouselView in Frameworks */,
205-
C54191392860AD9C00E29C3B /* JamitFoundation in Frameworks */,
206-
C541913B2860AD9C00E29C3B /* Keychain in Frameworks */,
207-
C541913D2860AD9C00E29C3B /* MessageView in Frameworks */,
208-
C54191472860AD9C00E29C3B /* WeakCache in Frameworks */,
209-
C54191452860AD9C00E29C3B /* UserDefaults in Frameworks */,
210-
C54191412860AD9C00E29C3B /* SwiftUISupport in Frameworks */,
211-
C541913F2860AD9C00E29C3B /* PageView in Frameworks */,
201+
C5DAE5CE299D26EB00CC8947 /* TimePickerView in Frameworks */,
202+
C5DAE5BE299D26EB00CC8947 /* BarcodeScanner in Frameworks */,
203+
C5DAE5C2299D26EB00CC8947 /* GridView in Frameworks */,
204+
C5DAE5C0299D26EB00CC8947 /* CarouselView in Frameworks */,
205+
C5DAE5C4299D26EB00CC8947 /* JamitFoundation in Frameworks */,
206+
C5DAE5C6299D26EB00CC8947 /* Keychain in Frameworks */,
207+
C5DAE5C8299D26EB00CC8947 /* MessageView in Frameworks */,
208+
C5DAE5D2299D26EB00CC8947 /* WeakCache in Frameworks */,
209+
C5DAE5D0299D26EB00CC8947 /* UserDefaults in Frameworks */,
210+
C5DAE5CC299D26EB00CC8947 /* SwiftUISupport in Frameworks */,
211+
C5DAE5CA299D26EB00CC8947 /* PageView in Frameworks */,
212212
);
213213
runOnlyForDeploymentPostprocessing = 0;
214214
};
@@ -622,17 +622,17 @@
622622
);
623623
name = JamitFoundationExample;
624624
packageProductDependencies = (
625-
C54191322860AD9C00E29C3B /* BarcodeScanner */,
626-
C54191342860AD9C00E29C3B /* CarouselView */,
627-
C54191362860AD9C00E29C3B /* GridView */,
628-
C54191382860AD9C00E29C3B /* JamitFoundation */,
629-
C541913A2860AD9C00E29C3B /* Keychain */,
630-
C541913C2860AD9C00E29C3B /* MessageView */,
631-
C541913E2860AD9C00E29C3B /* PageView */,
632-
C54191402860AD9C00E29C3B /* SwiftUISupport */,
633-
C54191422860AD9C00E29C3B /* TimePickerView */,
634-
C54191442860AD9C00E29C3B /* UserDefaults */,
635-
C54191462860AD9C00E29C3B /* WeakCache */,
625+
C5DAE5BD299D26EB00CC8947 /* BarcodeScanner */,
626+
C5DAE5BF299D26EB00CC8947 /* CarouselView */,
627+
C5DAE5C1299D26EB00CC8947 /* GridView */,
628+
C5DAE5C3299D26EB00CC8947 /* JamitFoundation */,
629+
C5DAE5C5299D26EB00CC8947 /* Keychain */,
630+
C5DAE5C7299D26EB00CC8947 /* MessageView */,
631+
C5DAE5C9299D26EB00CC8947 /* PageView */,
632+
C5DAE5CB299D26EB00CC8947 /* SwiftUISupport */,
633+
C5DAE5CD299D26EB00CC8947 /* TimePickerView */,
634+
C5DAE5CF299D26EB00CC8947 /* UserDefaults */,
635+
C5DAE5D1299D26EB00CC8947 /* WeakCache */,
636636
);
637637
productName = JamitFoundationExample;
638638
productReference = 1E1B3FE423F27E8700D9A6D5 /* JamitFoundationExample.app */;
@@ -707,7 +707,7 @@
707707
);
708708
mainGroup = 1E1B3FDB23F27E8700D9A6D5;
709709
packageReferences = (
710-
C54191312860AD9C00E29C3B /* XCRemoteSwiftPackageReference "JamitFoundation" */,
710+
C5DAE5BC299D26EB00CC8947 /* XCRemoteSwiftPackageReference "JamitFoundation" */,
711711
);
712712
productRefGroup = 1E1B3FE523F27E8700D9A6D5 /* Products */;
713713
projectDirPath = "";
@@ -1146,9 +1146,9 @@
11461146
/* End XCConfigurationList section */
11471147

11481148
/* Begin XCRemoteSwiftPackageReference section */
1149-
C54191312860AD9C00E29C3B /* XCRemoteSwiftPackageReference "JamitFoundation" */ = {
1149+
C5DAE5BC299D26EB00CC8947 /* XCRemoteSwiftPackageReference "JamitFoundation" */ = {
11501150
isa = XCRemoteSwiftPackageReference;
1151-
repositoryURL = "git@github.com:JamitLabs/JamitFoundation.git";
1151+
repositoryURL = "https://github.com/JamitLabs/JamitFoundation";
11521152
requirement = {
11531153
branch = "feature/swiftui-integration";
11541154
kind = branch;
@@ -1157,59 +1157,59 @@
11571157
/* End XCRemoteSwiftPackageReference section */
11581158

11591159
/* Begin XCSwiftPackageProductDependency section */
1160-
C54191322860AD9C00E29C3B /* BarcodeScanner */ = {
1160+
C5DAE5BD299D26EB00CC8947 /* BarcodeScanner */ = {
11611161
isa = XCSwiftPackageProductDependency;
1162-
package = C54191312860AD9C00E29C3B /* XCRemoteSwiftPackageReference "JamitFoundation" */;
1162+
package = C5DAE5BC299D26EB00CC8947 /* XCRemoteSwiftPackageReference "JamitFoundation" */;
11631163
productName = BarcodeScanner;
11641164
};
1165-
C54191342860AD9C00E29C3B /* CarouselView */ = {
1165+
C5DAE5BF299D26EB00CC8947 /* CarouselView */ = {
11661166
isa = XCSwiftPackageProductDependency;
1167-
package = C54191312860AD9C00E29C3B /* XCRemoteSwiftPackageReference "JamitFoundation" */;
1167+
package = C5DAE5BC299D26EB00CC8947 /* XCRemoteSwiftPackageReference "JamitFoundation" */;
11681168
productName = CarouselView;
11691169
};
1170-
C54191362860AD9C00E29C3B /* GridView */ = {
1170+
C5DAE5C1299D26EB00CC8947 /* GridView */ = {
11711171
isa = XCSwiftPackageProductDependency;
1172-
package = C54191312860AD9C00E29C3B /* XCRemoteSwiftPackageReference "JamitFoundation" */;
1172+
package = C5DAE5BC299D26EB00CC8947 /* XCRemoteSwiftPackageReference "JamitFoundation" */;
11731173
productName = GridView;
11741174
};
1175-
C54191382860AD9C00E29C3B /* JamitFoundation */ = {
1175+
C5DAE5C3299D26EB00CC8947 /* JamitFoundation */ = {
11761176
isa = XCSwiftPackageProductDependency;
1177-
package = C54191312860AD9C00E29C3B /* XCRemoteSwiftPackageReference "JamitFoundation" */;
1177+
package = C5DAE5BC299D26EB00CC8947 /* XCRemoteSwiftPackageReference "JamitFoundation" */;
11781178
productName = JamitFoundation;
11791179
};
1180-
C541913A2860AD9C00E29C3B /* Keychain */ = {
1180+
C5DAE5C5299D26EB00CC8947 /* Keychain */ = {
11811181
isa = XCSwiftPackageProductDependency;
1182-
package = C54191312860AD9C00E29C3B /* XCRemoteSwiftPackageReference "JamitFoundation" */;
1182+
package = C5DAE5BC299D26EB00CC8947 /* XCRemoteSwiftPackageReference "JamitFoundation" */;
11831183
productName = Keychain;
11841184
};
1185-
C541913C2860AD9C00E29C3B /* MessageView */ = {
1185+
C5DAE5C7299D26EB00CC8947 /* MessageView */ = {
11861186
isa = XCSwiftPackageProductDependency;
1187-
package = C54191312860AD9C00E29C3B /* XCRemoteSwiftPackageReference "JamitFoundation" */;
1187+
package = C5DAE5BC299D26EB00CC8947 /* XCRemoteSwiftPackageReference "JamitFoundation" */;
11881188
productName = MessageView;
11891189
};
1190-
C541913E2860AD9C00E29C3B /* PageView */ = {
1190+
C5DAE5C9299D26EB00CC8947 /* PageView */ = {
11911191
isa = XCSwiftPackageProductDependency;
1192-
package = C54191312860AD9C00E29C3B /* XCRemoteSwiftPackageReference "JamitFoundation" */;
1192+
package = C5DAE5BC299D26EB00CC8947 /* XCRemoteSwiftPackageReference "JamitFoundation" */;
11931193
productName = PageView;
11941194
};
1195-
C54191402860AD9C00E29C3B /* SwiftUISupport */ = {
1195+
C5DAE5CB299D26EB00CC8947 /* SwiftUISupport */ = {
11961196
isa = XCSwiftPackageProductDependency;
1197-
package = C54191312860AD9C00E29C3B /* XCRemoteSwiftPackageReference "JamitFoundation" */;
1197+
package = C5DAE5BC299D26EB00CC8947 /* XCRemoteSwiftPackageReference "JamitFoundation" */;
11981198
productName = SwiftUISupport;
11991199
};
1200-
C54191422860AD9C00E29C3B /* TimePickerView */ = {
1200+
C5DAE5CD299D26EB00CC8947 /* TimePickerView */ = {
12011201
isa = XCSwiftPackageProductDependency;
1202-
package = C54191312860AD9C00E29C3B /* XCRemoteSwiftPackageReference "JamitFoundation" */;
1202+
package = C5DAE5BC299D26EB00CC8947 /* XCRemoteSwiftPackageReference "JamitFoundation" */;
12031203
productName = TimePickerView;
12041204
};
1205-
C54191442860AD9C00E29C3B /* UserDefaults */ = {
1205+
C5DAE5CF299D26EB00CC8947 /* UserDefaults */ = {
12061206
isa = XCSwiftPackageProductDependency;
1207-
package = C54191312860AD9C00E29C3B /* XCRemoteSwiftPackageReference "JamitFoundation" */;
1207+
package = C5DAE5BC299D26EB00CC8947 /* XCRemoteSwiftPackageReference "JamitFoundation" */;
12081208
productName = UserDefaults;
12091209
};
1210-
C54191462860AD9C00E29C3B /* WeakCache */ = {
1210+
C5DAE5D1299D26EB00CC8947 /* WeakCache */ = {
12111211
isa = XCSwiftPackageProductDependency;
1212-
package = C54191312860AD9C00E29C3B /* XCRemoteSwiftPackageReference "JamitFoundation" */;
1212+
package = C5DAE5BC299D26EB00CC8947 /* XCRemoteSwiftPackageReference "JamitFoundation" */;
12131213
productName = WeakCache;
12141214
};
12151215
/* End XCSwiftPackageProductDependency section */

JamitFoundationExample/JamitFoundationExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"location" : "https://github.com/JamitLabs/JamitFoundation",
77
"state" : {
88
"branch" : "feature/swiftui-integration",
9-
"revision" : "1fa42c33edf20419ff1426d23972dc3b7c5e8b01"
9+
"revision" : "610261cee2ba951a7a6d680fb32416adc7ca0d63"
1010
}
1111
}
1212
],

Modules/SwiftUISupport/SwiftUIContainerView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class SwiftUIContainerView<ContentView: View>: StatefulView<EmptyViewMode
1111

1212
private lazy var hostingController: UIHostingController<AnyView> = {
1313
.init(
14-
rootView: AnyView(
14+
rootView: AnyView(
1515
contentView.environmentObject(
1616
NavigationCoordinator(
1717
navigationControllerProvider: self
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import JamitFoundation
2+
import SwiftUI
3+
import UIKit
4+
5+
@available(iOS 13.0, *)
6+
public struct UIKitNavigationLink<Label, Destination> : View where Label : View, Destination : View {
7+
@EnvironmentObject private var navigationCoordinator: NavigationCoordinator
8+
9+
private let destination: Destination
10+
private let label: Label
11+
12+
public init(@ViewBuilder destination: () -> Destination, @ViewBuilder label: () -> Label) {
13+
self.destination = destination()
14+
self.label = label()
15+
}
16+
17+
public init(destination: Destination, @ViewBuilder label: () -> Label) {
18+
self.destination = destination
19+
self.label = label()
20+
}
21+
22+
@MainActor public var body: some View {
23+
Button {
24+
navigationCoordinator.push(destination)
25+
} label: {
26+
label
27+
}
28+
}
29+
}
30+
31+
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
32+
extension UIKitNavigationLink where Label == Text {
33+
public init(_ titleKey: LocalizedStringKey, @ViewBuilder destination: () -> Destination) {
34+
self.init(destination: destination) {
35+
Text(titleKey)
36+
}
37+
}
38+
39+
public init<S>(_ title: S, @ViewBuilder destination: () -> Destination) where S : StringProtocol {
40+
self.init(destination: destination) {
41+
Text(title)
42+
}
43+
}
44+
45+
public init(_ titleKey: LocalizedStringKey, destination: Destination) {
46+
self.init(destination: destination) {
47+
Text(titleKey)
48+
}
49+
}
50+
51+
public init<S>(_ title: S, destination: Destination) where S : StringProtocol {
52+
self.init(destination: destination) {
53+
Text(title)
54+
}
55+
}
56+
}

0 commit comments

Comments
 (0)