diff --git a/.context/notes.md b/.context/notes.md new file mode 100644 index 0000000..e69de29 diff --git a/.context/todos.md b/.context/todos.md new file mode 100644 index 0000000..e69de29 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 55e1087..00081be 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -43,6 +43,7 @@ jobs: - platform=tvOS Simulator,name=Apple TV - platform=tvOS Simulator,name=Apple TV 4K (3rd generation) - platform=watchOS Simulator,name=Apple Watch Series 10 (46mm) + - platform=visionOS Simulator,name=Apple Vision Pro steps: - uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 3248e56..11b3c4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Add support for M5 iPad Pro models. ([#467](https://github.com/devicekit/DeviceKit/pull/467)) - Add support for Apple Watch SE (3rd generation) ([#473](https://github.com/devicekit/DeviceKit/pull/473)) - Add support for iPhone 17e and iPad Air (M4) +- Add support for Apple Vision Pro and Apple Vision Pro (M5) | Device | Case value | | --- | --- | @@ -17,6 +18,8 @@ | iPhone 17e | `Device.iPhone17e` | | iPad Air (11-inch) (M4) | `Device.iPadAir11M4` | | iPad Air (13-inch) (M4) | `Device.iPadAir13M4` | +| Apple Vision Pro | `Device.appleVisionPro` | +| Apple Vision Pro (M5) | `Device.appleVisionProM5` | ### Bug fixes diff --git a/Source/Device.generated.swift b/Source/Device.generated.swift index d67b11d..6209ca7 100644 --- a/Source/Device.generated.swift +++ b/Source/Device.generated.swift @@ -588,6 +588,15 @@ public enum Device { /// /// ![Image]() case appleWatchSeries11_46mm + #elseif os(visionOS) + /// Device is an [Apple Vision Pro](https://support.apple.com/kb/SP911) + /// + /// ![Image]() + case appleVisionPro + /// Device is an [Apple Vision Pro (M5)](https://support.apple.com/en-us/125436) + /// + /// ![Image]() + case appleVisionProM5 #endif /// Device is [Simulator](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/iOS_Simulator_Guide/Introduction/Introduction.html) @@ -774,8 +783,12 @@ public enum Device { default: return unknown(identifier) } #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return unknown(identifier) + switch identifier { + case "RealityDevice14,1": return appleVisionPro + case "RealityDevice17,1": return appleVisionProM5 + case "i386", "x86_64", "arm64": return simulator(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "visionOS")) + default: return unknown(identifier) + } #else return unknown(identifier) #endif @@ -1344,6 +1357,16 @@ public enum Device { public var hasForceTouchSupport: Bool { return isOneOf(Device.allWatchesWithForceTouchSupport) || isOneOf(Device.allWatchesWithForceTouchSupport.map(Device.simulator)) } + #elseif os(visionOS) + /// All Vision devices + public static var allVisions: [Device] { + return [.appleVisionPro, .appleVisionProM5] + } + + /// All simulator Vision devices + public static var allSimulatorVisions: [Device] { + return allVisions.map(Device.simulator) + } #endif /// Returns whether the current device is a SwiftUI preview canvas @@ -1365,8 +1388,7 @@ public enum Device { #elseif os(watchOS) return allWatches #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return [] + return allVisions #else return [] #endif @@ -1636,7 +1658,6 @@ public enum Device { #elseif os(tvOS) return nil #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. return nil #else return nil @@ -1821,8 +1842,12 @@ extension Device: CustomStringConvertible { case .unknown(let identifier): return identifier } #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return "Apple Vision Pro" + switch self { + case .appleVisionPro: return "Apple Vision Pro" + case .appleVisionProM5: return "Apple Vision Pro (M5)" + case .simulator(let model): return "Simulator (\(model.description))" + case .unknown(let identifier): return identifier + } #else switch self { case .simulator(let model): return "Simulator (\(model.description))" @@ -1986,8 +2011,12 @@ extension Device: CustomStringConvertible { case .unknown(let identifier): return identifier } #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return "Apple Vision Pro" + switch self { + case .appleVisionPro: return "Apple Vision Pro" + case .appleVisionProM5: return "Apple Vision Pro (M5)" + case .simulator(let model): return "Simulator (\(model.safeDescription))" + case .unknown(let identifier): return identifier + } #else switch self { case .simulator(let model): return "Simulator (\(model.safeDescription))" @@ -2508,7 +2537,7 @@ extension Device { extension Device { public enum CPU: Comparable { - #if os(iOS) || os(tvOS) + #if os(iOS) || os(tvOS) || os(visionOS) case a4 case a5 case a5X @@ -2707,8 +2736,12 @@ extension Device { case .unknown: return .unknown } #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return .unknown + switch self { + case .appleVisionPro: return .m2 + case .appleVisionProM5: return .m5 + case .simulator(let model): return model.cpu + case .unknown: return .unknown + } #else return .unknown #endif @@ -2719,7 +2752,7 @@ extension Device.CPU: CustomStringConvertible { /// A textual representation of the device. public var description: String { - #if os(iOS) || os(tvOS) + #if os(iOS) || os(tvOS) || os(visionOS) switch self { case .a4: return "A4" case .a5: return "A5" @@ -2768,9 +2801,6 @@ extension Device.CPU: CustomStringConvertible { case .s10: return "S10" case .unknown: return "unknown" } - #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return "unknown" #else return "unknown" #endif diff --git a/Source/Device.swift.gyb b/Source/Device.swift.gyb index 11a203e..97b6c90 100644 --- a/Source/Device.swift.gyb +++ b/Source/Device.swift.gyb @@ -156,6 +156,12 @@ tvs = [ Device("appleTV4K3", "Device is an [Apple TV 4K (3rd generation)](https://support.apple.com/kb/SP886)", "https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP886/apple-tv-4k-3gen_2x.png", ["AppleTV14,1"], 0, (), "Apple TV 4K (3rd generation)", "Apple TV 4K (3rd generation)", -1, False, False, False, False, False, False, False, False, False, False, 0, False, 0, False, "a15Bionic", False, False), ] +# visionOS +visions = [ + Device("appleVisionPro", "Device is an [Apple Vision Pro](https://support.apple.com/kb/SP911)", "", ["RealityDevice14,1"], 0, (1, 1), "Apple Vision Pro", "Apple Vision Pro", -1, False, False, False, False, False, False, False, False, False, False, 0, False, 0, True, "m2", True, False), + Device("appleVisionProM5", "Device is an [Apple Vision Pro (M5)](https://support.apple.com/en-us/125436)", "", ["RealityDevice17,1"], 0, (1, 1), "Apple Vision Pro (M5)", "Apple Vision Pro (M5)", -1, False, False, False, False, False, False, False, False, False, False, 0, False, 0, True, "m5", True, False), + ] + # watchOS watches = [ Device( @@ -361,6 +367,7 @@ watches = [ iOSDevices = iPods + iPhones + iPads + homePods tvOSDevices = tvs watchOSDevices = watches +visionOSDevices = visions }% #if os(watchOS) import WatchKit @@ -422,6 +429,13 @@ public enum Device { /// /// ![Image](${device.imageURL}) case ${device.caseName} +% end + #elseif os(visionOS) +% for device in visionOSDevices: + /// ${device.comment} + /// + /// ![Image](${device.imageURL}) + case ${device.caseName} % end #endif @@ -484,8 +498,13 @@ public enum Device { default: return unknown(identifier) } #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return unknown(identifier) + switch identifier { +% for device in visionOSDevices: + case ${', '.join(list(map(lambda device: "\"" + device + "\"", device.identifiers)))}: return ${device.caseName} +% end + case "i386", "x86_64", "arm64": return simulator(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "visionOS")) + default: return unknown(identifier) + } #else return unknown(identifier) #endif @@ -806,6 +825,16 @@ public enum Device { public var hasForceTouchSupport: Bool { return isOneOf(Device.allWatchesWithForceTouchSupport) || isOneOf(Device.allWatchesWithForceTouchSupport.map(Device.simulator)) } + #elseif os(visionOS) + /// All Vision devices + public static var allVisions: [Device] { + return [${', '.join(list(map(lambda device: "." + device.caseName, visionOSDevices)))}] + } + + /// All simulator Vision devices + public static var allSimulatorVisions: [Device] { + return allVisions.map(Device.simulator) + } #endif /// Returns whether the current device is a SwiftUI preview canvas @@ -827,8 +856,7 @@ public enum Device { #elseif os(watchOS) return allWatches #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return [] + return allVisions #else return [] #endif @@ -974,7 +1002,6 @@ public enum Device { #elseif os(tvOS) return nil #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. return nil #else return nil @@ -1034,8 +1061,13 @@ extension Device: CustomStringConvertible { case .unknown(let identifier): return identifier } #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return "Apple Vision Pro" + switch self { +% for device in visionOSDevices: + case .${device.caseName}: return "${device.description}" +% end + case .simulator(let model): return "Simulator (\(model.description))" + case .unknown(let identifier): return identifier + } #else switch self { case .simulator(let model): return "Simulator (\(model.description))" @@ -1074,8 +1106,13 @@ extension Device: CustomStringConvertible { case .unknown(let identifier): return identifier } #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return "Apple Vision Pro" + switch self { + % for device in visionOSDevices: + case .${device.caseName}: return "${device.safeDescription}" + % end + case .simulator(let model): return "Simulator (\(model.safeDescription))" + case .unknown(let identifier): return identifier + } #else switch self { case .simulator(let model): return "Simulator (\(model.safeDescription))" @@ -1568,7 +1605,7 @@ watchOS_cpus = [ extension Device { public enum CPU: Comparable { - #if os(iOS) || os(tvOS) + #if os(iOS) || os(tvOS) || os(visionOS) % for cpu in iOS_cpus: case ${cpu.name} % end @@ -1607,8 +1644,13 @@ extension Device { case .unknown: return .unknown } #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return .unknown + switch self { + % for device in visionOSDevices: + case .${device.caseName}: return .${device.cpu} + % end + case .simulator(let model): return model.cpu + case .unknown: return .unknown + } #else return .unknown #endif @@ -1619,7 +1661,7 @@ extension Device.CPU: CustomStringConvertible { /// A textual representation of the device. public var description: String { - #if os(iOS) || os(tvOS) + #if os(iOS) || os(tvOS) || os(visionOS) switch self { % for cpu in iOS_cpus: case .${cpu.name}: return "${cpu.description}" @@ -1633,9 +1675,6 @@ extension Device.CPU: CustomStringConvertible { % end case .unknown: return "unknown" } - #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return "unknown" #else return "unknown" #endif diff --git a/Tests/Tests.swift b/Tests/Tests.swift index 1e87af8..ebc5199 100644 --- a/Tests/Tests.swift +++ b/Tests/Tests.swift @@ -819,4 +819,30 @@ class DeviceKitTests: XCTestCase { #endif + // MARK: - visionOS + #if os(visionOS) + + func testMapFromIdentifier() { + XCTAssertEqual(Device.mapToDevice(identifier: "RealityDevice14,1"), .appleVisionPro) + XCTAssertEqual(Device.mapToDevice(identifier: "RealityDevice17,1"), .appleVisionProM5) + } + + func testDeviceCPU() { + XCTAssertEqual(Device.appleVisionPro.cpu, Device.CPU.m2) + XCTAssertEqual(Device.appleVisionProM5.cpu, Device.CPU.m5) + } + + func testDescription() { + XCTAssertEqual(Device.appleVisionPro.description, "Apple Vision Pro") + XCTAssertEqual(Device.appleVisionProM5.description, "Apple Vision Pro (M5)") + } + + func testSafeDescription() { + for device in Device.allRealDevices { + XCTAssertEqual(device.description, device.safeDescription) + } + } + + #endif + }