Skip to content

Commit fb2f27d

Browse files
authored
Add advanced range-based platform version predicates (#285)
1 parent 5ab4a22 commit fb2f27d

File tree

7 files changed

+477
-224
lines changed

7 files changed

+477
-224
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ Changelog
33

44
## master
55

6+
- Added: advanced range-based platform version predicates (#285)
7+
- Documentation: generate docs for extensions (#282)
8+
- Infrastructure: set up `tea` for CI and local environments (#276)
9+
610
## [0.7.0]
711

812
### SwiftUIIntrospect

Sources/Introspect.swift

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,27 @@ extension View {
2121
///
2222
/// - Parameters:
2323
/// - viewType: The type of view to be introspected.
24-
/// - platforms: A list of `PlatformViewVersions` that specify platform-specific entities associated with the view, with one or more corresponding version numbers.
25-
/// - scope: An optional `IntrospectionScope` that specifies the scope of introspection.
24+
/// - platforms: A list of version predicates that specify platform-specific entities associated with the view.
25+
/// - scope: Optionally overrides the view's default scope of introspection.
2626
/// - customize: A closure that hands over the underlying UIKit/AppKit instance ready for customization.
2727
///
2828
/// Here's an example usage:
2929
///
3030
/// ```swift
3131
/// struct ContentView: View {
32-
/// @State var date = Date()
32+
/// @State var text = ""
3333
///
3434
/// var body: some View {
35-
/// DatePicker("Pick a date", selection: $date)
36-
/// .introspect(.datePicker, on: .iOS(.v13, .v14, .v15, .v16, .v17)) {
37-
/// print(type(of: $0)) // UIDatePicker
35+
/// TextField("Placeholder", text: $text)
36+
/// .introspect(.textField, on: .iOS(.v13, .v14, .v15, .v16, .v17)) {
37+
/// print(type(of: $0)) // UITextField
3838
/// }
3939
/// }
4040
/// }
4141
/// ```
4242
public func introspect<SwiftUIViewType: IntrospectableViewType, PlatformSpecificEntity: PlatformEntity>(
4343
_ viewType: SwiftUIViewType,
44-
on platforms: (PlatformViewVersions<SwiftUIViewType, PlatformSpecificEntity>)...,
44+
on platforms: (PlatformViewVersionPredicate<SwiftUIViewType, PlatformSpecificEntity>)...,
4545
scope: IntrospectionScope? = nil,
4646
customize: @escaping (PlatformSpecificEntity) -> Void
4747
) -> some View {
@@ -57,16 +57,12 @@ struct IntrospectModifier<SwiftUIViewType: IntrospectableViewType, PlatformSpeci
5757

5858
init(
5959
_ viewType: SwiftUIViewType,
60-
platforms: [PlatformViewVersions<SwiftUIViewType, PlatformSpecificEntity>],
60+
platforms: [PlatformViewVersionPredicate<SwiftUIViewType, PlatformSpecificEntity>],
6161
scope: IntrospectionScope?,
6262
customize: @escaping (PlatformSpecificEntity) -> Void
6363
) {
6464
self.scope = scope ?? viewType.scope
65-
if let platform = platforms.first(where: \.isCurrent) {
66-
self.selector = platform.selector ?? .default
67-
} else {
68-
self.selector = nil
69-
}
65+
self.selector = platforms.lazy.compactMap(\.selector).first
7066
self.customize = customize
7167
}
7268

Sources/PlatformVersion.swift

Lines changed: 138 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,195 +1,275 @@
11
import Foundation
22

3+
public enum PlatformVersionCondition {
4+
case past
5+
case current
6+
case future
7+
}
8+
39
public protocol PlatformVersion {
4-
var isCurrent: Bool { get }
10+
var condition: PlatformVersionCondition? { get }
11+
}
12+
13+
extension PlatformVersion {
14+
public var isCurrent: Bool {
15+
condition == .current
16+
}
17+
18+
public var isCurrentOrPast: Bool {
19+
condition == .current || condition == .past
20+
}
521
}
622

723
public struct iOSVersion: PlatformVersion {
8-
public let isCurrent: Bool
24+
public let condition: PlatformVersionCondition?
925

10-
public init(isCurrent: () -> Bool) {
11-
self.isCurrent = isCurrent()
26+
public init(condition: () -> PlatformVersionCondition?) {
27+
self.condition = condition()
1228
}
1329
}
1430

1531
extension iOSVersion {
1632
public static let v13 = iOSVersion {
33+
#if os(iOS)
1734
if #available(iOS 14, *) {
18-
return false
35+
return .past
1936
}
2037
if #available(iOS 13, *) {
21-
return true
38+
return .current
2239
}
23-
return false
40+
return .future
41+
#else
42+
return nil
43+
#endif
2444
}
2545

2646
public static let v14 = iOSVersion {
47+
#if os(iOS)
2748
if #available(iOS 15, *) {
28-
return false
49+
return .past
2950
}
3051
if #available(iOS 14, *) {
31-
return true
52+
return .current
3253
}
33-
return false
54+
return .future
55+
#else
56+
return nil
57+
#endif
3458
}
3559

3660
public static let v15 = iOSVersion {
61+
#if os(iOS)
3762
if #available(iOS 16, *) {
38-
return false
63+
return .past
3964
}
4065
if #available(iOS 15, *) {
41-
return true
66+
return .current
4267
}
43-
return false
68+
return .future
69+
#else
70+
return nil
71+
#endif
4472
}
4573

4674
public static let v16 = iOSVersion {
75+
#if os(iOS)
4776
if #available(iOS 17, *) {
48-
return false
77+
return .past
4978
}
5079
if #available(iOS 16, *) {
51-
return true
80+
return .current
5281
}
53-
return false
82+
return .future
83+
#else
84+
return nil
85+
#endif
5486
}
5587

5688
public static let v17 = iOSVersion {
89+
#if os(iOS)
5790
if #available(iOS 18, *) {
58-
return false
91+
return .past
5992
}
6093
if #available(iOS 17, *) {
61-
return true
94+
return .current
6295
}
63-
return false
96+
return .future
97+
#else
98+
return nil
99+
#endif
64100
}
65101
}
66102

67103
public struct tvOSVersion: PlatformVersion {
68-
public let isCurrent: Bool
104+
public let condition: PlatformVersionCondition?
69105

70-
public init(isCurrent: () -> Bool) {
71-
self.isCurrent = isCurrent()
106+
public init(condition: () -> PlatformVersionCondition?) {
107+
self.condition = condition()
72108
}
73109
}
74110

75111
extension tvOSVersion {
76112
public static let v13 = tvOSVersion {
113+
#if os(tvOS)
77114
if #available(tvOS 14, *) {
78-
return false
115+
return .past
79116
}
80117
if #available(tvOS 13, *) {
81-
return true
118+
return .current
82119
}
83-
return false
120+
return .future
121+
#else
122+
return nil
123+
#endif
84124
}
85125

86126
public static let v14 = tvOSVersion {
127+
#if os(tvOS)
87128
if #available(tvOS 15, *) {
88-
return false
129+
return .past
89130
}
90131
if #available(tvOS 14, *) {
91-
return true
132+
return .current
92133
}
93-
return false
134+
return .future
135+
#else
136+
return nil
137+
#endif
94138
}
95139

96140
public static let v15 = tvOSVersion {
141+
#if os(tvOS)
97142
if #available(tvOS 16, *) {
98-
return false
143+
return .past
99144
}
100145
if #available(tvOS 15, *) {
101-
return true
146+
return .current
102147
}
103-
return false
148+
return .future
149+
#else
150+
return nil
151+
#endif
104152
}
105153

106154
public static let v16 = tvOSVersion {
155+
#if os(tvOS)
107156
if #available(tvOS 17, *) {
108-
return false
157+
return .past
109158
}
110159
if #available(tvOS 16, *) {
111-
return true
160+
return .current
112161
}
113-
return false
162+
return .future
163+
#else
164+
return nil
165+
#endif
114166
}
115167

116168
public static let v17 = tvOSVersion {
169+
#if os(tvOS)
117170
if #available(tvOS 18, *) {
118-
return false
171+
return .past
119172
}
120173
if #available(tvOS 17, *) {
121-
return true
174+
return .current
122175
}
123-
return false
176+
return .future
177+
#else
178+
return nil
179+
#endif
124180
}
125181
}
126182

127183
public struct macOSVersion: PlatformVersion {
128-
public let isCurrent: Bool
184+
public let condition: PlatformVersionCondition?
129185

130-
public init(isCurrent: () -> Bool) {
131-
self.isCurrent = isCurrent()
186+
public init(condition: () -> PlatformVersionCondition?) {
187+
self.condition = condition()
132188
}
133189
}
134190

135191
extension macOSVersion {
136192
public static let v10_15 = macOSVersion {
193+
#if os(macOS)
137194
if #available(macOS 11, *) {
138-
return false
195+
return .past
139196
}
140197
if #available(macOS 10.15, *) {
141-
return true
198+
return .current
142199
}
143-
return false
200+
return .future
201+
#else
202+
return nil
203+
#endif
144204
}
145205

146206
public static let v10_15_4 = macOSVersion {
207+
#if os(macOS)
147208
if #available(macOS 11, *) {
148-
return false
209+
return .past
149210
}
150211
if #available(macOS 10.15.4, *) {
151-
return true
212+
return .current
152213
}
153-
return false
214+
return .future
215+
#else
216+
return nil
217+
#endif
154218
}
155219

156220
public static let v11 = macOSVersion {
221+
#if os(macOS)
157222
if #available(macOS 12, *) {
158-
return false
223+
return .past
159224
}
160225
if #available(macOS 11, *) {
161-
return true
226+
return .current
162227
}
163-
return false
228+
return .future
229+
#else
230+
return nil
231+
#endif
164232
}
165233

166234
public static let v12 = macOSVersion {
235+
#if os(macOS)
167236
if #available(macOS 13, *) {
168-
return false
237+
return .past
169238
}
170239
if #available(macOS 12, *) {
171-
return true
240+
return .current
172241
}
173-
return false
242+
return .future
243+
#else
244+
return nil
245+
#endif
174246
}
175247

176248
public static let v13 = macOSVersion {
249+
#if os(macOS)
177250
if #available(macOS 14, *) {
178-
return false
251+
return .past
179252
}
180253
if #available(macOS 13, *) {
181-
return true
254+
return .current
182255
}
183-
return false
256+
return .future
257+
#else
258+
return nil
259+
#endif
184260
}
185261

186262
public static let v14 = macOSVersion {
263+
#if os(macOS)
187264
if #available(macOS 15, *) {
188-
return false
265+
return .past
189266
}
190267
if #available(macOS 14, *) {
191-
return true
268+
return .current
192269
}
193-
return false
270+
return .future
271+
#else
272+
return nil
273+
#endif
194274
}
195275
}

0 commit comments

Comments
 (0)