From 6eee28c908ffca0ad2c20f02f4774194448d4654 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 17 Nov 2025 21:11:12 +0000 Subject: [PATCH 1/7] Initial plan From 24d55ca6451c042f9f858012920f8c8ef47d0241 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 17 Nov 2025 21:16:16 +0000 Subject: [PATCH 2/7] Fix Apple Pencil compatibility for iPad models Co-authored-by: Zandor300 <6069593+Zandor300@users.noreply.github.com> # Conflicts: # Source/Device.generated.swift # Conflicts: # Source/Device.generated.swift # Source/Device.swift.gyb --- Source/Device.generated.swift | 16 ++++++++-------- Source/Device.swift.gyb | 19 +++++++++++-------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/Source/Device.generated.swift b/Source/Device.generated.swift index 48c6acd..8f52886 100644 --- a/Source/Device.generated.swift +++ b/Source/Device.generated.swift @@ -2239,8 +2239,8 @@ extension Device { case .iPadPro12Inch: return .firstGeneration case .iPadPro12Inch2: return .firstGeneration case .iPadPro10Inch: return .firstGeneration - case .iPad10: return .firstGenerationUsbC - case .iPadA16: return .firstGenerationUsbC + case .iPad10: return [.firstGeneration, .firstGenerationUsbC] + case .iPadA16: return [.firstGeneration, .firstGenerationUsbC] case .iPadAir4: return [.secondGeneration, .firstGenerationUsbC] case .iPadAir5: return [.secondGeneration, .firstGenerationUsbC] case .iPadMini6: return [.secondGeneration, .firstGenerationUsbC] @@ -2252,15 +2252,15 @@ extension Device { case .iPadPro12Inch5: return [.secondGeneration, .firstGenerationUsbC] case .iPadPro11Inch4: return [.secondGeneration, .firstGenerationUsbC] case .iPadPro12Inch6: return [.secondGeneration, .firstGenerationUsbC] - case .iPadPro11M4: return [.secondGeneration, .firstGenerationUsbC, .pro] - case .iPadPro13M4: return [.secondGeneration, .firstGenerationUsbC, .pro] case .iPadPro11M5: return [.secondGeneration, .firstGenerationUsbC, .pro] case .iPadPro13M5: return [.secondGeneration, .firstGenerationUsbC, .pro] - case .iPadAir11M2: return [.secondGeneration, .pro] - case .iPadAir13M2: return [.secondGeneration, .pro] - case .iPadAir11M3: return [.secondGeneration, .pro] - case .iPadAir13M3: return [.secondGeneration, .pro] + case .iPadAir11M2: return [.firstGenerationUsbC, .pro] + case .iPadAir13M2: return [.firstGenerationUsbC, .pro] + case .iPadAir11M3: return [.firstGenerationUsbC, .pro] + case .iPadAir13M3: return [.firstGenerationUsbC, .pro] case .iPadMiniA17Pro: return [.firstGenerationUsbC, .pro] + case .iPadPro11M4: return [.firstGenerationUsbC, .pro] + case .iPadPro13M4: return [.firstGenerationUsbC, .pro] case .simulator(let model): return model.applePencilSupport default: return [] } diff --git a/Source/Device.swift.gyb b/Source/Device.swift.gyb index f17ee6b..66cdd26 100644 --- a/Source/Device.swift.gyb +++ b/Source/Device.swift.gyb @@ -109,14 +109,14 @@ iPads = [ Device("iPad7", "Device is an [iPad (7th generation)](https://support.apple.com/kb/SP807)", "https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP807/sp807-ipad-7th-gen_2x.png", ["iPad7,11", "iPad7,12"], 10.2, (3, 4), "iPad (7th generation)", "iPad (7th generation)", 264, False, False, False, False, True, False, False, False, False, False, 1, False, 1, False, "a10Fusion", False, False), Device("iPad8", "Device is an [iPad (8th generation)](https://support.apple.com/kb/SP822)", "https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP822/sp822-ipad-8gen_2x.png", ["iPad11,6", "iPad11,7"], 10.2, (3, 4), "iPad (8th generation)", "iPad (8th generation)", 264, False, False, False, False, True, False, False, False, False, False, 1, False, 1, False, "a12Bionic", False, False), Device("iPad9", "Device is an [iPad (9th generation)](https://support.apple.com/kb/SP849)", "https://km.support.apple.com/resources/sites/APPLE/content/live/IMAGES/1000/IM1096/en_US/ipad-9gen-240.png", ["iPad12,1", "iPad12,2"], 10.2, (3, 4), "iPad (9th generation)", "iPad (9th generation)", 264, False, False, False, False, True, False, False, False, False, False, 1, False, 1, False, "a13Bionic", False, False), - Device("iPad10", "Device is an [iPad (10th generation)](https://support.apple.com/kb/SP884)", "https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP884/sp884-ipad-10gen-960_2x.png", ["iPad13,18", "iPad13,19"], 10.9, (41, 59), "iPad (10th generation)", "iPad (10th generation)", 264, False, False, False, False, True, False, False, False, True, False, 3, False, 1, False, "a14Bionic", True, True), - Device("iPadA16", "Device is an [iPad (A16)]()", "", ["iPad15,7", "iPad15,8"], 10.9, (41, 59), "iPad (A16)", "iPad (A16)", 264, False, False, False, False, True, False, False, False, True, False, 3, False, 1, False, "a16Bionic", True, True), + Device("iPad10", "Device is an [iPad (10th generation)](https://support.apple.com/kb/SP884)", "https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP884/sp884-ipad-10gen-960_2x.png", ["iPad13,18", "iPad13,19"], 10.9, (41, 59), "iPad (10th generation)", "iPad (10th generation)", 264, False, False, False, False, True, False, False, False, True, False, 13, False, 1, False, "a14Bionic", True, True), + Device("iPadA16", "Device is an [iPad (A16)]()", "", ["iPad15,7", "iPad15,8"], 10.9, (41, 59), "iPad (A16)", "iPad (A16)", 264, False, False, False, False, True, False, False, False, True, False, 13, False, 1, False, "a16Bionic", True, True), Device("iPadAir4", "Device is an [iPad Air (4th generation)](https://support.apple.com/kb/SP828)", "https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP828/sp828ipad-air-ipados14-960_2x.png", ["iPad13,1", "iPad13,2"], 10.9, (41, 59), "iPad Air (4th generation)", "iPad Air (4th generation)", 264, False, False, False, False, True, False, False, False, True, False, 23, False, 1, False, "a14Bionic", True, False), Device("iPadAir5", "Device is an [iPad Air (5th generation)](https://support.apple.com/kb/SP866)", "https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP866/sp866-ipad-air-5gen_2x.png", ["iPad13,16", "iPad13,17"], 10.9, (41, 59), "iPad Air (5th generation)", "iPad Air (5th generation)", 264, False, False, False, False, True, False, False, False, True, False, 23, False, 1, False, "m1", True, True), - Device("iPadAir11M2", "Device is an [iPad Air 11-inch (M2)](https://support.apple.com/en-us/119894)", "https://cdsassets.apple.com/content/services/pub/image?productid=301027&size=240x240", ["iPad14,8", "iPad14,9"], 10.9, (59, 41), "iPad Air (11-inch) (M2)", "iPad Air (11-inch) (M2)", 264, False, False, False, False, True, False, False, False, True, False, 24, False, 1, False, "m2", True, True), - Device("iPadAir13M2", "Device is an [iPad Air 13-inch (M2)](https://support.apple.com/en-us/119893)", "https://cdsassets.apple.com/content/services/pub/image?productid=301029&size=240x240", ["iPad14,10", "iPad14,11"], 12.9, (683, 512), "iPad Air (13-inch) (M2)", "iPad Air (13-inch) (M2)", 264, False, False, False, False, True, False, False, False, True, False, 24, False, 1, False, "m2", True, True), - Device("iPadAir11M3", "Device is an [iPad Air 11-inch (M3)]()", "https://cdsassets.apple.com/content/services/pub/image?productid=301027&size=240x240", ["iPad15,3", "iPad15,4"], 10.9, (59, 41), "iPad Air (11-inch) (M3)", "iPad Air (11-inch) (M3)", 264, False, False, False, False, True, False, False, False, True, False, 24, False, 1, False, "m3", True, True), - Device("iPadAir13M3", "Device is an [iPad Air 13-inch (M3)]()", "https://cdsassets.apple.com/content/services/pub/image?productid=301029&size=240x240", ["iPad15,5", "iPad15,6"], 12.9, (683, 512), "iPad Air (13-inch) (M3)", "iPad Air (13-inch) (M3)", 264, False, False, False, False, True, False, False, False, True, False, 24, False, 1, False, "m3", True, True), + Device("iPadAir11M2", "Device is an [iPad Air 11-inch (M2)](https://support.apple.com/en-us/119894)", "https://cdsassets.apple.com/content/services/pub/image?productid=301027&size=240x240", ["iPad14,8", "iPad14,9"], 10.9, (59, 41), "iPad Air (11-inch) (M2)", "iPad Air (11-inch) (M2)", 264, False, False, False, False, True, False, False, False, True, False, 34, False, 1, False, "m2", True, True), + Device("iPadAir13M2", "Device is an [iPad Air 13-inch (M2)](https://support.apple.com/en-us/119893)", "https://cdsassets.apple.com/content/services/pub/image?productid=301029&size=240x240", ["iPad14,10", "iPad14,11"], 12.9, (683, 512), "iPad Air (13-inch) (M2)", "iPad Air (13-inch) (M2)", 264, False, False, False, False, True, False, False, False, True, False, 34, False, 1, False, "m2", True, True), + Device("iPadAir11M3", "Device is an [iPad Air 11-inch (M3)]()", "https://cdsassets.apple.com/content/services/pub/image?productid=301027&size=240x240", ["iPad15,3", "iPad15,4"], 10.9, (59, 41), "iPad Air (11-inch) (M3)", "iPad Air (11-inch) (M3)", 264, False, False, False, False, True, False, False, False, True, False, 34, False, 1, False, "m3", True, True), + Device("iPadAir13M3", "Device is an [iPad Air 13-inch (M3)]()", "https://cdsassets.apple.com/content/services/pub/image?productid=301029&size=240x240", ["iPad15,5", "iPad15,6"], 12.9, (683, 512), "iPad Air (13-inch) (M3)", "iPad Air (13-inch) (M3)", 264, False, False, False, False, True, False, False, False, True, False, 34, False, 1, False, "m3", True, True), Device("iPadMini", "Device is an [iPad Mini](https://support.apple.com/kb/SP661)", "https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP661/sp661_ipad_mini_color.jpg", ["iPad2,5", "iPad2,6", "iPad2,7"], 7.9, (3, 4), "iPad Mini", "iPad Mini", 163, False, True, False, False, False, False, False, False, False, False, 0, False, 1, False, "a5", False, False), Device("iPadMini2", "Device is an [iPad Mini 2](https://support.apple.com/kb/SP693)", "https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP693/SP693-specs_color-mul.png", ["iPad4,4", "iPad4,5", "iPad4,6"], 7.9, (3, 4), "iPad Mini 2", "iPad Mini 2", 326, False, True, False, False, False, False, False, False, False, False, 0, False, 1, False, "a7", False, False), Device("iPadMini3", "Device is an [iPad Mini 3](https://support.apple.com/kb/SP709)", "https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP709/SP709-space_gray.jpeg", ["iPad4,7", "iPad4,8", "iPad4,9"], 7.9, (3, 4), "iPad Mini 3", "iPad Mini 3", 326, False, True, False, False, True, False, False, False, False, False, 0, False, 1, False, "a7", False, False), @@ -136,8 +136,8 @@ iPads = [ Device("iPadPro12Inch5", "Device is an [iPad Pro 12.9-inch (5th generation)](https://support.apple.com/kb/SP844)", "https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP844/ipad-pro-12-9_2x.png", ["iPad13,8", "iPad13,9", "iPad13,10", "iPad13,11"], 12.9, (512, 683), "iPad Pro (12.9-inch) (5th generation)", "iPad Pro (12.9-inch) (5th generation)", 264, False, False, True, False, False, True, False, False, True, False, 23, False, 13, True, "m1", True, True), Device("iPadPro11Inch4", "Device is an [iPad Pro 11-inch (4th generation)](https://support.apple.com/kb/SP882)", "https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP882/ipad-pro-4gen-mainimage_2x.png", ["iPad14,3", "iPad14,4"], 11.0, (139, 199), "iPad Pro (11-inch) (4th generation)", "iPad Pro (11-inch) (4th generation)", 264, False, False, True, False, False, True, False, False, True, False, 23, False, 13, True, "m2", True, True), Device("iPadPro12Inch6", "Device is an [iPad Pro 12.9-inch (6th generation)](https://support.apple.com/kb/SP883)", "https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP882/ipad-pro-4gen-mainimage_2x.png", ["iPad14,5", "iPad14,6"], 12.9, (512, 683), "iPad Pro (12.9-inch) (6th generation)", "iPad Pro (12.9-inch) (6th generation)", 264, False, False, True, False, False, True, False, False, True, False, 23, False, 13, True, "m2", True, True), - Device("iPadPro11M4", "Device is an [iPad Pro 11-inch (M4)](https://support.apple.com/en-us/119892)", "https://cdsassets.apple.com/content/services/pub/image?productid=301031&size=240x240", ["iPad16,3", "iPad16,4"], 11.0, (605, 417), "iPad Pro (11-inch) (M4)", "iPad Pro (11-inch) (M4)", 264, False, False, True, False, False, True, False, False, True, False, 234, False, 1, True, "m4", True, True), - Device("iPadPro13M4", "Device is an [iPad Pro 13-inch (M4)](https://support.apple.com/en-us/119891)", "https://cdsassets.apple.com/content/services/pub/image?productid=301033&size=240x240", ["iPad16,5", "iPad16,6"], 13.0, (4, 3), "iPad Pro (13-inch) (M4)", "iPad Pro (13-inch) (M4)", 264, False, False, True, False, False, True, False, False, True, False, 234, False, 1, True, "m4", True, True), + Device("iPadPro11M4", "Device is an [iPad Pro 11-inch (M4)](https://support.apple.com/en-us/119892)", "https://cdsassets.apple.com/content/services/pub/image?productid=301031&size=240x240", ["iPad16,3", "iPad16,4"], 11.0, (605, 417), "iPad Pro (11-inch) (M4)", "iPad Pro (11-inch) (M4)", 264, False, False, True, False, False, True, False, False, True, False, 34, False, 1, True, "m4", True, True), + Device("iPadPro13M4", "Device is an [iPad Pro 13-inch (M4)](https://support.apple.com/en-us/119891)", "https://cdsassets.apple.com/content/services/pub/image?productid=301033&size=240x240", ["iPad16,5", "iPad16,6"], 13.0, (4, 3), "iPad Pro (13-inch) (M4)", "iPad Pro (13-inch) (M4)", 264, False, False, True, False, False, True, False, False, True, False, 34, False, 1, True, "m4", True, True), Device("iPadPro11M5", "Device is an [iPad Pro 11-inch (M5)](https://support.apple.com/en-us/125406)", "", ["iPad17,3", "iPad17,4"], 11.0, (605, 417), "iPad Pro (11-inch) (M5)", "iPad Pro (11-inch) (M5)", 264, False, False, True, False, False, True, False, False, True, False, 234, False, 1, True, "m5", True, True), Device("iPadPro13M5", "Device is an [iPad Pro 13-inch (M5)](https://support.apple.com/en-us/125406)", "", ["iPad17,5", "iPad17,6"], 13.0, (4, 3), "iPad Pro (13-inch) (M5)", "iPad Pro (13-inch) (M5)", 264, False, False, True, False, False, True, False, False, True, False, 234, False, 1, True, "m5", True, True), ] @@ -1356,6 +1356,9 @@ extension Device { % for device in list(filter(lambda device: device.applePencilSupport == 4, iOSDevices)): case .${device.caseName}: return [.pro] % end + % for device in list(filter(lambda device: device.applePencilSupport == 13, iOSDevices)): + case .${device.caseName}: return [.firstGeneration, .firstGenerationUsbC] + % end % for device in list(filter(lambda device: device.applePencilSupport == 23, iOSDevices)): case .${device.caseName}: return [.secondGeneration, .firstGenerationUsbC] % end From 01e4d5661211bd06364cb3e74045934db3281267 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 17 Nov 2025 21:18:10 +0000 Subject: [PATCH 3/7] Add tests for Apple Pencil compatibility Co-authored-by: Zandor300 <6069593+Zandor300@users.noreply.github.com> --- Tests/Tests.swift | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/Tests/Tests.swift b/Tests/Tests.swift index d59d324..8f67211 100644 --- a/Tests/Tests.swift +++ b/Tests/Tests.swift @@ -727,6 +727,56 @@ class DeviceKitTests: XCTestCase { } } + func testApplePencilSupport() { + // Test iPad (10th gen) - Supports Apple Pencil (1st gen) and Apple Pencil (USB-C) + XCTAssertTrue(Device.iPad10.applePencilSupport.contains(.firstGeneration)) + XCTAssertTrue(Device.iPad10.applePencilSupport.contains(.firstGenerationUsbC)) + XCTAssertFalse(Device.iPad10.applePencilSupport.contains(.secondGeneration)) + XCTAssertFalse(Device.iPad10.applePencilSupport.contains(.pro)) + + // Test iPad (A16) - Supports Apple Pencil (1st gen) and Apple Pencil (USB-C) + XCTAssertTrue(Device.iPadA16.applePencilSupport.contains(.firstGeneration)) + XCTAssertTrue(Device.iPadA16.applePencilSupport.contains(.firstGenerationUsbC)) + XCTAssertFalse(Device.iPadA16.applePencilSupport.contains(.secondGeneration)) + XCTAssertFalse(Device.iPadA16.applePencilSupport.contains(.pro)) + + // Test iPad Air 11" (M2) - Supports Apple Pencil Pro and Apple Pencil (USB-C) + XCTAssertFalse(Device.iPadAir11M2.applePencilSupport.contains(.firstGeneration)) + XCTAssertTrue(Device.iPadAir11M2.applePencilSupport.contains(.firstGenerationUsbC)) + XCTAssertFalse(Device.iPadAir11M2.applePencilSupport.contains(.secondGeneration)) + XCTAssertTrue(Device.iPadAir11M2.applePencilSupport.contains(.pro)) + + // Test iPad Air 13" (M2) - Supports Apple Pencil Pro and Apple Pencil (USB-C) + XCTAssertFalse(Device.iPadAir13M2.applePencilSupport.contains(.firstGeneration)) + XCTAssertTrue(Device.iPadAir13M2.applePencilSupport.contains(.firstGenerationUsbC)) + XCTAssertFalse(Device.iPadAir13M2.applePencilSupport.contains(.secondGeneration)) + XCTAssertTrue(Device.iPadAir13M2.applePencilSupport.contains(.pro)) + + // Test iPad Air 11" (M3) - Supports Apple Pencil Pro and Apple Pencil (USB-C) + XCTAssertFalse(Device.iPadAir11M3.applePencilSupport.contains(.firstGeneration)) + XCTAssertTrue(Device.iPadAir11M3.applePencilSupport.contains(.firstGenerationUsbC)) + XCTAssertFalse(Device.iPadAir11M3.applePencilSupport.contains(.secondGeneration)) + XCTAssertTrue(Device.iPadAir11M3.applePencilSupport.contains(.pro)) + + // Test iPad Air 13" (M3) - Supports Apple Pencil Pro and Apple Pencil (USB-C) + XCTAssertFalse(Device.iPadAir13M3.applePencilSupport.contains(.firstGeneration)) + XCTAssertTrue(Device.iPadAir13M3.applePencilSupport.contains(.firstGenerationUsbC)) + XCTAssertFalse(Device.iPadAir13M3.applePencilSupport.contains(.secondGeneration)) + XCTAssertTrue(Device.iPadAir13M3.applePencilSupport.contains(.pro)) + + // Test iPad Pro 11" (M4) - Supports Apple Pencil Pro and Apple Pencil (USB-C) + XCTAssertFalse(Device.iPadPro11M4.applePencilSupport.contains(.firstGeneration)) + XCTAssertTrue(Device.iPadPro11M4.applePencilSupport.contains(.firstGenerationUsbC)) + XCTAssertFalse(Device.iPadPro11M4.applePencilSupport.contains(.secondGeneration)) + XCTAssertTrue(Device.iPadPro11M4.applePencilSupport.contains(.pro)) + + // Test iPad Pro 13" (M4) - Supports Apple Pencil Pro and Apple Pencil (USB-C) + XCTAssertFalse(Device.iPadPro13M4.applePencilSupport.contains(.firstGeneration)) + XCTAssertTrue(Device.iPadPro13M4.applePencilSupport.contains(.firstGenerationUsbC)) + XCTAssertFalse(Device.iPadPro13M4.applePencilSupport.contains(.secondGeneration)) + XCTAssertTrue(Device.iPadPro13M4.applePencilSupport.contains(.pro)) + } + #endif // MARK: - tvOS From 0c0450c044d6de7faefb17ae3a7c53c2379e03c6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Dec 2025 09:56:07 +0000 Subject: [PATCH 4/7] Add changelog entry and fix trailing whitespace in tests Co-authored-by: Zandor300 <6069593+Zandor300@users.noreply.github.com> --- CHANGELOG.md | 1 + Tests/Tests.swift | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bc2fbd..651aedf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ This version adds support for the iPhone 17 series, Apple Watch Ultra 3 and Appl - Missing device identifiers for Apple Watch Series 9 were added. - Docs for Apple Watch Series 9 was updated to include specs links - Fixed Apple Pencil support for iPad Mini (A17 Pro). +- Fixed Apple Pencil compatibility for M4 iPad Pro, M2/M3 iPad Air, iPad (10th gen), and iPad (A16) models. Thanks to all the contributers of this release! - [Jager-yoo](https://github.com/Jager-yoo) diff --git a/Tests/Tests.swift b/Tests/Tests.swift index 8f67211..e80a2fe 100644 --- a/Tests/Tests.swift +++ b/Tests/Tests.swift @@ -733,43 +733,43 @@ class DeviceKitTests: XCTestCase { XCTAssertTrue(Device.iPad10.applePencilSupport.contains(.firstGenerationUsbC)) XCTAssertFalse(Device.iPad10.applePencilSupport.contains(.secondGeneration)) XCTAssertFalse(Device.iPad10.applePencilSupport.contains(.pro)) - + // Test iPad (A16) - Supports Apple Pencil (1st gen) and Apple Pencil (USB-C) XCTAssertTrue(Device.iPadA16.applePencilSupport.contains(.firstGeneration)) XCTAssertTrue(Device.iPadA16.applePencilSupport.contains(.firstGenerationUsbC)) XCTAssertFalse(Device.iPadA16.applePencilSupport.contains(.secondGeneration)) XCTAssertFalse(Device.iPadA16.applePencilSupport.contains(.pro)) - + // Test iPad Air 11" (M2) - Supports Apple Pencil Pro and Apple Pencil (USB-C) XCTAssertFalse(Device.iPadAir11M2.applePencilSupport.contains(.firstGeneration)) XCTAssertTrue(Device.iPadAir11M2.applePencilSupport.contains(.firstGenerationUsbC)) XCTAssertFalse(Device.iPadAir11M2.applePencilSupport.contains(.secondGeneration)) XCTAssertTrue(Device.iPadAir11M2.applePencilSupport.contains(.pro)) - + // Test iPad Air 13" (M2) - Supports Apple Pencil Pro and Apple Pencil (USB-C) XCTAssertFalse(Device.iPadAir13M2.applePencilSupport.contains(.firstGeneration)) XCTAssertTrue(Device.iPadAir13M2.applePencilSupport.contains(.firstGenerationUsbC)) XCTAssertFalse(Device.iPadAir13M2.applePencilSupport.contains(.secondGeneration)) XCTAssertTrue(Device.iPadAir13M2.applePencilSupport.contains(.pro)) - + // Test iPad Air 11" (M3) - Supports Apple Pencil Pro and Apple Pencil (USB-C) XCTAssertFalse(Device.iPadAir11M3.applePencilSupport.contains(.firstGeneration)) XCTAssertTrue(Device.iPadAir11M3.applePencilSupport.contains(.firstGenerationUsbC)) XCTAssertFalse(Device.iPadAir11M3.applePencilSupport.contains(.secondGeneration)) XCTAssertTrue(Device.iPadAir11M3.applePencilSupport.contains(.pro)) - + // Test iPad Air 13" (M3) - Supports Apple Pencil Pro and Apple Pencil (USB-C) XCTAssertFalse(Device.iPadAir13M3.applePencilSupport.contains(.firstGeneration)) XCTAssertTrue(Device.iPadAir13M3.applePencilSupport.contains(.firstGenerationUsbC)) XCTAssertFalse(Device.iPadAir13M3.applePencilSupport.contains(.secondGeneration)) XCTAssertTrue(Device.iPadAir13M3.applePencilSupport.contains(.pro)) - + // Test iPad Pro 11" (M4) - Supports Apple Pencil Pro and Apple Pencil (USB-C) XCTAssertFalse(Device.iPadPro11M4.applePencilSupport.contains(.firstGeneration)) XCTAssertTrue(Device.iPadPro11M4.applePencilSupport.contains(.firstGenerationUsbC)) XCTAssertFalse(Device.iPadPro11M4.applePencilSupport.contains(.secondGeneration)) XCTAssertTrue(Device.iPadPro11M4.applePencilSupport.contains(.pro)) - + // Test iPad Pro 13" (M4) - Supports Apple Pencil Pro and Apple Pencil (USB-C) XCTAssertFalse(Device.iPadPro13M4.applePencilSupport.contains(.firstGeneration)) XCTAssertTrue(Device.iPadPro13M4.applePencilSupport.contains(.firstGenerationUsbC)) From a87bb5d76be6c836098a18cfb355817ae18cd11a Mon Sep 17 00:00:00 2001 From: Zandor Smith Date: Wed, 3 Dec 2025 20:30:52 +0100 Subject: [PATCH 5/7] Fix linting issues. --- .swiftlint.yml | 1 + .../Contents.swift | 5 ++-- Package.swift | 4 +-- Source/Device.generated.swift | 2 +- Source/Device.swift.gyb | 2 +- Tests/Tests.swift | 25 +++++++++---------- 6 files changed, 20 insertions(+), 19 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index 6e309ef..5324912 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -4,6 +4,7 @@ disabled_rules: - switch_case_alignment - type_body_length - identifier_name + - trailing_comma opt_in_rules: - anyobject_protocol diff --git a/Example/DeviceKitPlayground.playground/Contents.swift b/Example/DeviceKitPlayground.playground/Contents.swift index 95d7931..14a1a74 100644 --- a/Example/DeviceKitPlayground.playground/Contents.swift +++ b/Example/DeviceKitPlayground.playground/Contents.swift @@ -96,8 +96,9 @@ if Device.volumeAvailableCapacityForImportantUsage ?? 0 > Int64(1_000) { // Get the underlying device let simulator = Device.simulator(.iPhone8Plus) let realDevice = Device.iPhone8Plus -simulator.realDevice == realDevice // true -realDevice.realDevice == realDevice // true + +_ = simulator.realDevice == realDevice // true +_ = realDevice.realDevice == realDevice // true // Get device thermal state if device.thermalState == .nominal { diff --git a/Package.swift b/Package.swift index 55e14ab..a2443b0 100644 --- a/Package.swift +++ b/Package.swift @@ -1,5 +1,5 @@ // swift-tools-version:5.3 -//===----------------------------------------------------------------------===// +// ===----------------------------------------------------------------------=== // // // This source file is part of the DeviceKit open source project // @@ -8,7 +8,7 @@ // License: https://github.com/dennisweissmann/DeviceKit/blob/master/LICENSE // Contributors: https://github.com/dennisweissmann/DeviceKit#contributors // -//===----------------------------------------------------------------------===// +// ===----------------------------------------------------------------------=== // import PackageDescription diff --git a/Source/Device.generated.swift b/Source/Device.generated.swift index 8f52886..f074d3a 100644 --- a/Source/Device.generated.swift +++ b/Source/Device.generated.swift @@ -2167,7 +2167,7 @@ extension Device { /// The volume’s available capacity in bytes for storing nonessential resources. @available(iOS 11.0, *) - public static var volumeAvailableCapacityForOpportunisticUsage: Int64? { //swiftlint:disable:this identifier_name + public static var volumeAvailableCapacityForOpportunisticUsage: Int64? { // swiftlint:disable:this identifier_name return (try? rootURL.resourceValues(forKeys: [.volumeAvailableCapacityForOpportunisticUsageKey]))?.volumeAvailableCapacityForOpportunisticUsage } diff --git a/Source/Device.swift.gyb b/Source/Device.swift.gyb index 66cdd26..b5ae58a 100644 --- a/Source/Device.swift.gyb +++ b/Source/Device.swift.gyb @@ -1282,7 +1282,7 @@ extension Device { /// The volume’s available capacity in bytes for storing nonessential resources. @available(iOS 11.0, *) - public static var volumeAvailableCapacityForOpportunisticUsage: Int64? { //swiftlint:disable:this identifier_name + public static var volumeAvailableCapacityForOpportunisticUsage: Int64? { // swiftlint:disable:this identifier_name return (try? rootURL.resourceValues(forKeys: [.volumeAvailableCapacityForOpportunisticUsageKey]))?.volumeAvailableCapacityForOpportunisticUsage } diff --git a/Tests/Tests.swift b/Tests/Tests.swift index e80a2fe..fd40c26 100644 --- a/Tests/Tests.swift +++ b/Tests/Tests.swift @@ -1,4 +1,4 @@ -//===----------------------------------------------------------------------===// +// ===----------------------------------------------------------------------=== // // // This source file is part of the DeviceKit open source project // @@ -7,7 +7,7 @@ // License: https://github.com/dennisweissmann/DeviceKit/blob/master/LICENSE // Contributors: https://github.com/dennisweissmann/DeviceKit#contributors // -//===----------------------------------------------------------------------===// +// ===----------------------------------------------------------------------=== // @testable import DeviceKit import XCTest @@ -331,7 +331,7 @@ class DeviceKitTests: XCTestCase { XCTAssertEqual(Device.unknown(UUID().uuidString).diagonal, -1) } - func testDescription() { // swiftlint:disable:this function_body_length + func testDescription() { XCTAssertEqual(Device.iPodTouch5.description, "iPod touch (5th generation)") XCTAssertEqual(Device.iPodTouch6.description, "iPod touch (6th generation)") XCTAssertEqual(Device.iPodTouch7.description, "iPod touch (7th generation)") @@ -626,16 +626,15 @@ class DeviceKitTests: XCTestCase { XCTAssertTrue(device.hasCamera) XCTAssertTrue(device.hasWideCamera || device.hasTelephotoCamera || device.hasUltraWideCamera) } - for device in Device.allPhones + Device.allPads + Device.allPods { - if !Device.allDevicesWithCamera.contains(device) { - XCTAssertFalse(device.cameras.contains(.wide)) - XCTAssertFalse(device.cameras.contains(.telephoto)) - XCTAssertFalse(device.cameras.contains(.ultraWide)) - XCTAssertFalse(device.hasCamera) - XCTAssertFalse(device.hasWideCamera) - XCTAssertFalse(device.hasTelephotoCamera) - XCTAssertFalse(device.hasUltraWideCamera) - } + let devices = Device.allPhones + Device.allPads + Device.allPods + for device in devices where !Device.allDevicesWithCamera.contains(device) { + XCTAssertFalse(device.cameras.contains(.wide)) + XCTAssertFalse(device.cameras.contains(.telephoto)) + XCTAssertFalse(device.cameras.contains(.ultraWide)) + XCTAssertFalse(device.hasCamera) + XCTAssertFalse(device.hasWideCamera) + XCTAssertFalse(device.hasTelephotoCamera) + XCTAssertFalse(device.hasUltraWideCamera) } for device in Device.allDevicesWithWideCamera { XCTAssertTrue(device.cameras.contains(.wide)) From 4b66d8f93d467bffc759fc630e68e5d06604b3b7 Mon Sep 17 00:00:00 2001 From: Zandor Smith Date: Wed, 3 Dec 2025 20:32:51 +0100 Subject: [PATCH 6/7] Fix changelog entry. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 651aedf..8835ea8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ ### Bug fixes - Fixed iPhone Air incorrectly marked as having ultra-wide camera. ([#463](https://github.com/devicekit/DeviceKit/pull/463)) +- Fixed Apple Pencil compatibility for M4 iPad Pro, M2/M3 iPad Air, iPad (10th gen), and iPad (A16) models. ([#474](https://github.com/devicekit/DeviceKit/pull/474)) ## Version 5.7.0 @@ -45,7 +46,6 @@ This version adds support for the iPhone 17 series, Apple Watch Ultra 3 and Appl - Missing device identifiers for Apple Watch Series 9 were added. - Docs for Apple Watch Series 9 was updated to include specs links - Fixed Apple Pencil support for iPad Mini (A17 Pro). -- Fixed Apple Pencil compatibility for M4 iPad Pro, M2/M3 iPad Air, iPad (10th gen), and iPad (A16) models. Thanks to all the contributers of this release! - [Jager-yoo](https://github.com/Jager-yoo) From a50c6287b9669029acbf860537a8603927fff33e Mon Sep 17 00:00:00 2001 From: Zandor Smith Date: Wed, 3 Dec 2025 20:48:13 +0100 Subject: [PATCH 7/7] Fix additional linting issues. --- .swiftlint.yml | 1 + Source/Device.generated.swift | 2 +- Source/Device.swift.gyb | 2 +- Tests/Tests.swift | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index 5324912..beaf51f 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -5,6 +5,7 @@ disabled_rules: - type_body_length - identifier_name - trailing_comma + - function_body_length opt_in_rules: - anyobject_protocol diff --git a/Source/Device.generated.swift b/Source/Device.generated.swift index f074d3a..23a4d81 100644 --- a/Source/Device.generated.swift +++ b/Source/Device.generated.swift @@ -611,7 +611,7 @@ public enum Device { /// - parameter identifier: The device identifier, e.g. "iPhone7,1". Can be obtained from `Device.identifier`. /// /// - returns: An initialized `Device`. - public static func mapToDevice(identifier: String) -> Device { // swiftlint:disable:this cyclomatic_complexity function_body_length + public static func mapToDevice(identifier: String) -> Device { #if os(iOS) switch identifier { case "iPod5,1": return iPodTouch5 diff --git a/Source/Device.swift.gyb b/Source/Device.swift.gyb index b5ae58a..3d55a1b 100644 --- a/Source/Device.swift.gyb +++ b/Source/Device.swift.gyb @@ -455,7 +455,7 @@ public enum Device { /// - parameter identifier: The device identifier, e.g. "iPhone7,1". Can be obtained from `Device.identifier`. /// /// - returns: An initialized `Device`. - public static func mapToDevice(identifier: String) -> Device { // swiftlint:disable:this cyclomatic_complexity function_body_length + public static func mapToDevice(identifier: String) -> Device { #if os(iOS) switch identifier { % for device in iOSDevices: diff --git a/Tests/Tests.swift b/Tests/Tests.swift index fd40c26..defea19 100644 --- a/Tests/Tests.swift +++ b/Tests/Tests.swift @@ -162,7 +162,7 @@ class DeviceKitTests: XCTestCase { XCTAssertTrue(Device.BatteryState.unplugged(2) > Device.BatteryState.charging(1)) } - func testMapFromIdentifier() { // swiftlint:disable:this function_body_length + func testMapFromIdentifier() { XCTAssertEqual(Device.mapToDevice(identifier: "iPod5,1"), .iPodTouch5) XCTAssertEqual(Device.mapToDevice(identifier: "iPod7,1"), .iPodTouch6) XCTAssertEqual(Device.mapToDevice(identifier: "iPhone3,1"), .iPhone4)