From e51468b43e1b6e21ec9c4e06006050d09e6cfaf5 Mon Sep 17 00:00:00 2001 From: Vincent Neo <23420208+vincentneo@users.noreply.github.com> Date: Sat, 12 Sep 2026 00:13:53 +0800 Subject: [PATCH 01/10] Add iPhone 18 Pro series, Duo, watches model --- Sources/DeviceModel.swift | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Sources/DeviceModel.swift b/Sources/DeviceModel.swift index 96710ac..5a9b1e5 100644 --- a/Sources/DeviceModel.swift +++ b/Sources/DeviceModel.swift @@ -51,6 +51,8 @@ public enum DeviceModel: CaseIterable { case iPhone17e case iPhone17Pro, iPhone17ProMax case iPhoneAir + case iPhone18Pro, iPhone18ProMax + case iPhoneDuo case iPadFirstGen, iPadSecondGen, iPadThirdGen, iPadFourthGen, iPadFifthGen, iPadSixthGen, iPadSeventhGen, iPadEighthGen, iPadNinthGen, iPadTenthGen case iPadA16 @@ -97,6 +99,8 @@ public enum DeviceModel: CaseIterable { case series11 case ultra3 case se3 + case series12 + case ultra4 #endif case unknown @@ -202,6 +206,11 @@ extension DeviceModel { case (18, 3): return .iPhone17 case (18, 4): return .iPhoneAir case (18, 5): return .iPhone17e + + case (19, 2): return .iPhone18Pro + case (19, 3): return .iPhone18ProMax // Qualcomm modem, sold in the US only? + case (19, 4): return .iPhoneDuo + case (19, 7): return .iPhone18ProMax // Apple C2 modem, sold internationally? default: return .unknown } @@ -328,6 +337,8 @@ extension DeviceModel { case (7, 17), (7, 18), (7, 19), (7, 20): return .series11 case (7, 12): return .ultra3 case (7, 13), (7, 14), (7, 15), (7, 16): return .se3 + case (8, 1): return .ultra4 + case (8, 2), (8, 3), (8, 4), (8, 5): return .series12 default: return .unknown } } @@ -370,10 +381,21 @@ extension DeviceModel { return true case .iPhoneAir, .iPhone17, .iPhone17Pro, .iPhone17ProMax: return true + case .iPhone18Pro, .iPhone18ProMax: + return true default: return false } } + + public var isFoldable: Bool { + switch self { + case .iPhoneDuo: + return true + default: + return false + } + } } #endif From 53e3e2e44119984d4cf8f973d7b8fd776259802c Mon Sep 17 00:00:00 2001 From: Vincent Neo <23420208+vincentneo@users.noreply.github.com> Date: Sat, 12 Sep 2026 00:15:04 +0800 Subject: [PATCH 02/10] Add Ultra 4 / Series 12 watches identifier --- Sources/Identifier.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Sources/Identifier.swift b/Sources/Identifier.swift index 511fc5d..62598fc 100644 --- a/Sources/Identifier.swift +++ b/Sources/Identifier.swift @@ -570,6 +570,16 @@ extension Identifier: CustomStringConvertible { return "Apple Watch Series 11, 42mm case (GPS + Cellular)" case (7, 20): return "Apple Watch Series 11, 46mm case (GPS + Cellular)" + case (8, 1): + return "Apple Watch Ultra 4" + case (8, 2): + return "Apple Watch Series 12, 42mm case (GPS)" + case (8, 3): + return "Apple Watch Series 12, 46mm case (GPS)" + case (8, 4): + return "Apple Watch Series 12, 42mm case (GPS + Cellular)" + case (8, 5): + return "Apple Watch Series 12, 46mm case (GPS + Cellular)" default: return "unknown" } From 0480e2157ae67911504e3a1e53eb8b6336c144b6 Mon Sep 17 00:00:00 2001 From: Vincent Neo <23420208+vincentneo@users.noreply.github.com> Date: Sat, 12 Sep 2026 00:17:07 +0800 Subject: [PATCH 03/10] Add iPhone 18 Pro / Max, Duo identifiers --- Sources/Identifier.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Sources/Identifier.swift b/Sources/Identifier.swift index 62598fc..96ffaa0 100644 --- a/Sources/Identifier.swift +++ b/Sources/Identifier.swift @@ -212,6 +212,14 @@ extension Identifier: CustomStringConvertible { case (18, 5): return "iPhone 17e" + case (19, 2): + return "iPhone 18 Pro" + case (19, 3): + return "iPhone 18 Pro Max" // Qualcomm modem, sold in the US only? + case (19, 4): + return "iPhone Duo" + case (19, 7): + return "iPhone 18 Pro Max" // Apple C2 modem, sold internationally? default: return "unknown" From 84438b122c007ce326e3cc6489709ba2198e984c Mon Sep 17 00:00:00 2001 From: Vincent Neo <23420208+vincentneo@users.noreply.github.com> Date: Sat, 12 Sep 2026 00:19:35 +0800 Subject: [PATCH 04/10] Update watch screen sizes --- Sources/Screen.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Sources/Screen.swift b/Sources/Screen.swift index a4162d8..8334726 100644 --- a/Sources/Screen.swift +++ b/Sources/Screen.swift @@ -139,10 +139,12 @@ extension Screen { case (6, 7), (6, 9), (6, 15), (6, 17), (7, 2), (7, 4): return .medium(mm: 45) - case (6, 18), (7, 5), (7, 12): return .ultra(mm: 49) + case (6, 18), (7, 5), (7, 12), (8, 1): return .ultra(mm: 49) - case (7, 8), (7, 10), (7, 17), (7, 19): return .small(mm: 42) - case (7, 9), (7, 11), (7, 18), (7, 20): return .medium(mm: 46) + case (7, 8), (7, 10), (7, 17), (7, 19), + (8, 2), (8, 4): return .small(mm: 42) + case (7, 9), (7, 11), (7, 18), (7, 20), + (8, 3), (8, 5): return .medium(mm: 46) default: return nil } From 1d8548b3df202e8a3677bc726b9384cc5facb612 Mon Sep 17 00:00:00 2001 From: Vincent Neo <23420208+vincentneo@users.noreply.github.com> Date: Sat, 12 Sep 2026 00:00:59 +0800 Subject: [PATCH 05/10] split job --- .github/workflows/swift.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index ea50e23..288e589 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -4,12 +4,18 @@ run-name: Build smoke test by ${{ github.actor }} on: [push, pull_request] jobs: - test: + test-iOS: name: Test UIDeviceComplete runs-on: macos-latest steps: - uses: actions/checkout@v2 - name: Test (iOS) run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -project "UIDeviceComplete.xcodeproj" -scheme "UIDeviceComplete" -destination "OS=latest,name=iPhone 17 Pro Max" clean test | xcpretty + + test-watchOS: + name: Test UIDeviceComplete + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 - name: Test (watchOS) run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -project "UIDeviceComplete.xcodeproj" -scheme "UIDeviceComplete" -destination "OS=latest,name=Apple Watch Series 11 (46mm)" clean test | xcpretty From 748caf355f726fb1a3d0d0c1b8c8936a50265617 Mon Sep 17 00:00:00 2001 From: Vincent Neo <23420208+vincentneo@users.noreply.github.com> Date: Sat, 12 Sep 2026 00:06:44 +0800 Subject: [PATCH 06/10] Rename workflow jobs --- .github/workflows/swift.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 288e589..f980211 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -5,17 +5,17 @@ on: [push, pull_request] jobs: test-iOS: - name: Test UIDeviceComplete + name: Test (iOS) runs-on: macos-latest steps: - uses: actions/checkout@v2 - - name: Test (iOS) + - name: Test run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -project "UIDeviceComplete.xcodeproj" -scheme "UIDeviceComplete" -destination "OS=latest,name=iPhone 17 Pro Max" clean test | xcpretty test-watchOS: - name: Test UIDeviceComplete + name: Test (watchOS) runs-on: macos-latest steps: - uses: actions/checkout@v2 - - name: Test (watchOS) + - name: Test run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -project "UIDeviceComplete.xcodeproj" -scheme "UIDeviceComplete" -destination "OS=latest,name=Apple Watch Series 11 (46mm)" clean test | xcpretty From 73799ac8fe770bcd003b5f989a9b319ef26b06e1 Mon Sep 17 00:00:00 2001 From: Vincent Neo <23420208+vincentneo@users.noreply.github.com> Date: Sat, 12 Sep 2026 00:28:24 +0800 Subject: [PATCH 07/10] fix notch and dynamic island tests --- Tests/DeviceModelTests.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Tests/DeviceModelTests.swift b/Tests/DeviceModelTests.swift index 911518d..84fe39d 100644 --- a/Tests/DeviceModelTests.swift +++ b/Tests/DeviceModelTests.swift @@ -537,7 +537,7 @@ class DeviceModelTests: XCTestCase { .iPhone12, .iPhone12Pro, .iPhone12ProMax, .iPhone12mini, .iPhone13, .iPhone13mini, .iPhone13Pro, .iPhone13ProMax, .iPhone14, .iPhone14Plus, - .iPhone16e] + .iPhone16e, .iPhone17e] let noNotchModels: [DeviceModel] = DeviceModel.allCases.filter( { !notchModels.contains($0) }) @@ -550,7 +550,8 @@ class DeviceModelTests: XCTestCase { func testHasDynamicIsland() { let withModels: [DeviceModel] = [.iPhone14Pro, .iPhone14ProMax, .iPhone15, .iPhone15Plus, .iPhone15Pro, .iPhone15ProMax, - .iPhone16, .iPhone16Plus, .iPhone16Pro, .iPhone16ProMax] + .iPhone16, .iPhone16Plus, .iPhone16Pro, .iPhone16ProMax, + .iPhone17, .iPhoneAir, .iPhone17Pro, .iPhone17ProMax] let withoutModels: [DeviceModel] = DeviceModel.allCases.filter( { !withModels.contains($0) }) From e8cfc9eeecf34c12d4b237a06a478a15025b4f63 Mon Sep 17 00:00:00 2001 From: Vincent Neo <23420208+vincentneo@users.noreply.github.com> Date: Sat, 12 Sep 2026 00:32:36 +0800 Subject: [PATCH 08/10] Update dynamic island tests for 18 Pro/Max --- Tests/DeviceModelTests.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tests/DeviceModelTests.swift b/Tests/DeviceModelTests.swift index 84fe39d..147e602 100644 --- a/Tests/DeviceModelTests.swift +++ b/Tests/DeviceModelTests.swift @@ -551,7 +551,8 @@ class DeviceModelTests: XCTestCase { let withModels: [DeviceModel] = [.iPhone14Pro, .iPhone14ProMax, .iPhone15, .iPhone15Plus, .iPhone15Pro, .iPhone15ProMax, .iPhone16, .iPhone16Plus, .iPhone16Pro, .iPhone16ProMax, - .iPhone17, .iPhoneAir, .iPhone17Pro, .iPhone17ProMax] + .iPhone17, .iPhoneAir, .iPhone17Pro, .iPhone17ProMax, + .iPhone18Pro, .iPhone18ProMax] let withoutModels: [DeviceModel] = DeviceModel.allCases.filter( { !withModels.contains($0) }) From 250f6122591e65068b9304cf816d4905e859d8b0 Mon Sep 17 00:00:00 2001 From: Vincent Neo <23420208+vincentneo@users.noreply.github.com> Date: Sat, 12 Sep 2026 00:40:18 +0800 Subject: [PATCH 09/10] Add October 2025 iPad Pro/Air models --- Sources/DeviceModel.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Sources/DeviceModel.swift b/Sources/DeviceModel.swift index 5a9b1e5..c722c68 100644 --- a/Sources/DeviceModel.swift +++ b/Sources/DeviceModel.swift @@ -61,6 +61,7 @@ public enum DeviceModel: CaseIterable { case iPadAir11InchM2, iPadAir13InchM2 case iPadAir11InchM3, iPadAir13InchM3 + case iPadAir11InchM4, iPadAir13InchM4 case iPadMini, iPadMini2, iPadMini3, iPadMini4, iPadMini5, iPadMini6 case iPadMiniA17Pro @@ -76,6 +77,7 @@ public enum DeviceModel: CaseIterable { case iPadPro11Inch_FourthGen, iPadPro12_9Inch_SixthGen case iPadPro11InchM4, iPadPro13InchM4 + case iPadPro11InchM5, iPadPro13InchM5 case iPodTouchFirstGen, iPodTouchSecondGen, iPodTouchThirdGen, iPodTouchFourthGen, iPodTouchFifthGen, iPodTouchSixthGen, iPodTouchSeventhGen @@ -250,6 +252,8 @@ extension DeviceModel { case (14, 10), (14, 11): return .iPadAir13InchM2 case (15, 3), (15, 4): return .iPadAir11InchM3 case (15, 5), (15, 6): return .iPadAir13InchM3 + case (16, 8), (15, 9): return .iPadAir11InchM4 + case (16, 10), (16, 11): return .iPadAir13InchM4 case (2, 5), (2, 6), (2, 7): return .iPadMini case (4, 4), (4, 5), (4, 6): return .iPadMini2 @@ -279,6 +283,10 @@ extension DeviceModel { return .iPadPro11InchM4 case (16, 5), (16, 6): return .iPadPro13InchM4 + case (17, 1), (17, 2): + return .iPadPro11InchM5 + case (17, 3), (17, 4): + return .iPadPro13InchM5 default: return .unknown } } From d5d443e694e60282c8aff87c94088e59a8f8023d Mon Sep 17 00:00:00 2001 From: Vincent Neo <23420208+vincentneo@users.noreply.github.com> Date: Sat, 12 Sep 2026 00:42:57 +0800 Subject: [PATCH 10/10] Add Oct 2025 iPads identifier --- Sources/Identifier.swift | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Sources/Identifier.swift b/Sources/Identifier.swift index 96ffaa0..b984b05 100644 --- a/Sources/Identifier.swift +++ b/Sources/Identifier.swift @@ -456,6 +456,24 @@ extension Identifier: CustomStringConvertible { return "iPad Air M3 (13 inch, Wi-Fi)" case (15, 7): return "iPad Air M3 (13 inch, Wi-Fi+5G)" + + case (16, 8): + return "iPad Air M4 (11 inch, Wi-Fi)" + case (16, 9): + return "iPad Air M4 (11 inch, Wi-Fi+5G)" + case (16, 10): + return "iPad Air M4 (13 inch, Wi-Fi)" + case (16, 11): + return "iPad Air M4 (13 inch, Wi-Fi+5G)" + + case (17, 1): + return "iPad Pro M5 (11 inch, Wi-Fi)" + case (17, 2): + return "iPad Pro M5 (11 inch, Wi-Fi+5G)" + case (17, 3): + return "iPad Pro M5 (13 inch, Wi-Fi)" + case (17, 4): + return "iPad Pro M5 (13 inch, Wi-Fi+5G)" default: return "unknown"