Skip to content

Add advanced range-based platform version predicates #285

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jul 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ Changelog

## master

- Added: advanced range-based platform version predicates (#285)
- Documentation: generate docs for extensions (#282)
- Infrastructure: set up `tea` for CI and local environments (#276)

## [0.7.0]

### SwiftUIIntrospect
Expand Down
22 changes: 9 additions & 13 deletions Sources/Introspect.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,27 @@ extension View {
///
/// - Parameters:
/// - viewType: The type of view to be introspected.
/// - platforms: A list of `PlatformViewVersions` that specify platform-specific entities associated with the view, with one or more corresponding version numbers.
/// - scope: An optional `IntrospectionScope` that specifies the scope of introspection.
/// - platforms: A list of version predicates that specify platform-specific entities associated with the view.
/// - scope: Optionally overrides the view's default scope of introspection.
/// - customize: A closure that hands over the underlying UIKit/AppKit instance ready for customization.
///
/// Here's an example usage:
///
/// ```swift
/// struct ContentView: View {
/// @State var date = Date()
/// @State var text = ""
///
/// var body: some View {
/// DatePicker("Pick a date", selection: $date)
/// .introspect(.datePicker, on: .iOS(.v13, .v14, .v15, .v16, .v17)) {
/// print(type(of: $0)) // UIDatePicker
/// TextField("Placeholder", text: $text)
/// .introspect(.textField, on: .iOS(.v13, .v14, .v15, .v16, .v17)) {
/// print(type(of: $0)) // UITextField
/// }
/// }
/// }
/// ```
public func introspect<SwiftUIViewType: IntrospectableViewType, PlatformSpecificEntity: PlatformEntity>(
_ viewType: SwiftUIViewType,
on platforms: (PlatformViewVersions<SwiftUIViewType, PlatformSpecificEntity>)...,
on platforms: (PlatformViewVersionPredicate<SwiftUIViewType, PlatformSpecificEntity>)...,
scope: IntrospectionScope? = nil,
customize: @escaping (PlatformSpecificEntity) -> Void
) -> some View {
Expand All @@ -57,16 +57,12 @@ struct IntrospectModifier<SwiftUIViewType: IntrospectableViewType, PlatformSpeci

init(
_ viewType: SwiftUIViewType,
platforms: [PlatformViewVersions<SwiftUIViewType, PlatformSpecificEntity>],
platforms: [PlatformViewVersionPredicate<SwiftUIViewType, PlatformSpecificEntity>],
scope: IntrospectionScope?,
customize: @escaping (PlatformSpecificEntity) -> Void
) {
self.scope = scope ?? viewType.scope
if let platform = platforms.first(where: \.isCurrent) {
self.selector = platform.selector ?? .default
} else {
self.selector = nil
}
self.selector = platforms.lazy.compactMap(\.selector).first
self.customize = customize
}

Expand Down
196 changes: 138 additions & 58 deletions Sources/PlatformVersion.swift
Original file line number Diff line number Diff line change
@@ -1,195 +1,275 @@
import Foundation

public enum PlatformVersionCondition {
case past
case current
case future
}

public protocol PlatformVersion {
var isCurrent: Bool { get }
var condition: PlatformVersionCondition? { get }
}

extension PlatformVersion {
public var isCurrent: Bool {
condition == .current
}

public var isCurrentOrPast: Bool {
condition == .current || condition == .past
}
}

public struct iOSVersion: PlatformVersion {
public let isCurrent: Bool
public let condition: PlatformVersionCondition?

public init(isCurrent: () -> Bool) {
self.isCurrent = isCurrent()
public init(condition: () -> PlatformVersionCondition?) {
self.condition = condition()
}
}

extension iOSVersion {
public static let v13 = iOSVersion {
#if os(iOS)
if #available(iOS 14, *) {
return false
return .past
}
if #available(iOS 13, *) {
return true
return .current
}
return false
return .future
#else
return nil
#endif
}

public static let v14 = iOSVersion {
#if os(iOS)
if #available(iOS 15, *) {
return false
return .past
}
if #available(iOS 14, *) {
return true
return .current
}
return false
return .future
#else
return nil
#endif
}

public static let v15 = iOSVersion {
#if os(iOS)
if #available(iOS 16, *) {
return false
return .past
}
if #available(iOS 15, *) {
return true
return .current
}
return false
return .future
#else
return nil
#endif
}

public static let v16 = iOSVersion {
#if os(iOS)
if #available(iOS 17, *) {
return false
return .past
}
if #available(iOS 16, *) {
return true
return .current
}
return false
return .future
#else
return nil
#endif
}

public static let v17 = iOSVersion {
#if os(iOS)
if #available(iOS 18, *) {
return false
return .past
}
if #available(iOS 17, *) {
return true
return .current
}
return false
return .future
#else
return nil
#endif
}
}

public struct tvOSVersion: PlatformVersion {
public let isCurrent: Bool
public let condition: PlatformVersionCondition?

public init(isCurrent: () -> Bool) {
self.isCurrent = isCurrent()
public init(condition: () -> PlatformVersionCondition?) {
self.condition = condition()
}
}

extension tvOSVersion {
public static let v13 = tvOSVersion {
#if os(tvOS)
if #available(tvOS 14, *) {
return false
return .past
}
if #available(tvOS 13, *) {
return true
return .current
}
return false
return .future
#else
return nil
#endif
}

public static let v14 = tvOSVersion {
#if os(tvOS)
if #available(tvOS 15, *) {
return false
return .past
}
if #available(tvOS 14, *) {
return true
return .current
}
return false
return .future
#else
return nil
#endif
}

public static let v15 = tvOSVersion {
#if os(tvOS)
if #available(tvOS 16, *) {
return false
return .past
}
if #available(tvOS 15, *) {
return true
return .current
}
return false
return .future
#else
return nil
#endif
}

public static let v16 = tvOSVersion {
#if os(tvOS)
if #available(tvOS 17, *) {
return false
return .past
}
if #available(tvOS 16, *) {
return true
return .current
}
return false
return .future
#else
return nil
#endif
}

public static let v17 = tvOSVersion {
#if os(tvOS)
if #available(tvOS 18, *) {
return false
return .past
}
if #available(tvOS 17, *) {
return true
return .current
}
return false
return .future
#else
return nil
#endif
}
}

public struct macOSVersion: PlatformVersion {
public let isCurrent: Bool
public let condition: PlatformVersionCondition?

public init(isCurrent: () -> Bool) {
self.isCurrent = isCurrent()
public init(condition: () -> PlatformVersionCondition?) {
self.condition = condition()
}
}

extension macOSVersion {
public static let v10_15 = macOSVersion {
#if os(macOS)
if #available(macOS 11, *) {
return false
return .past
}
if #available(macOS 10.15, *) {
return true
return .current
}
return false
return .future
#else
return nil
#endif
}

public static let v10_15_4 = macOSVersion {
#if os(macOS)
if #available(macOS 11, *) {
return false
return .past
}
if #available(macOS 10.15.4, *) {
return true
return .current
}
return false
return .future
#else
return nil
#endif
}

public static let v11 = macOSVersion {
#if os(macOS)
if #available(macOS 12, *) {
return false
return .past
}
if #available(macOS 11, *) {
return true
return .current
}
return false
return .future
#else
return nil
#endif
}

public static let v12 = macOSVersion {
#if os(macOS)
if #available(macOS 13, *) {
return false
return .past
}
if #available(macOS 12, *) {
return true
return .current
}
return false
return .future
#else
return nil
#endif
}

public static let v13 = macOSVersion {
#if os(macOS)
if #available(macOS 14, *) {
return false
return .past
}
if #available(macOS 13, *) {
return true
return .current
}
return false
return .future
#else
return nil
#endif
}

public static let v14 = macOSVersion {
#if os(macOS)
if #available(macOS 15, *) {
return false
return .past
}
if #available(macOS 14, *) {
return true
return .current
}
return false
return .future
#else
return nil
#endif
}
}
Loading