Skip to content
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

Addition of devices introduced in 2024, minor clean up for iPad content #99

Closed
wants to merge 14 commits into from
Closed
25 changes: 23 additions & 2 deletions Sources/DeviceModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,14 @@ public enum DeviceModel: CaseIterable {
case iPhone14Pro, iPhone14ProMax
case iPhone15, iPhone15Plus
case iPhone15Pro, iPhone15ProMax
case iPhone16, iPhone16Plus
case iPhone16Pro, iPhone16ProMax

case iPadFirstGen, iPadSecondGen, iPadThirdGen, iPadFourthGen, iPadFifthGen, iPadSixthGen, iPadSeventhGen, iPadEighthGen, iPadNinthGen, iPadTenthGen

case iPadAir, iPadAir2, iPadAir3, iPadAir4, iPadAir5

case iPadAir11InchM2, iPadAir13InchM2

case iPadMini, iPadMini2, iPadMini3, iPadMini4, iPadMini5, iPadMini6

Expand All @@ -60,6 +64,8 @@ public enum DeviceModel: CaseIterable {
case iPadPro11Inch_ThirdGen, iPadPro12_9Inch_FifthGen

case iPadPro11Inch_FourthGen, iPadPro12_9Inch_SixthGen

case iPadPro11InchM4, iPadPro13InchM4

case iPodTouchFirstGen, iPodTouchSecondGen, iPodTouchThirdGen,
iPodTouchFourthGen, iPodTouchFifthGen, iPodTouchSixthGen, iPodTouchSeventhGen
Expand All @@ -79,6 +85,7 @@ public enum DeviceModel: CaseIterable {
case ultra
case series9
case ultra2
case series10
#endif

case unknown
Expand Down Expand Up @@ -172,6 +179,11 @@ extension DeviceModel {

case (16, 1): return .iPhone15Pro
case (16, 2): return .iPhone15ProMax

case (17, 1): return .iPhone16Pro
case (17, 2): return .iPhone16ProMax
case (17, 3): return .iPhone16
case (17, 4): return .iPhone16Plus

default: return .unknown
}
Expand Down Expand Up @@ -205,6 +217,10 @@ extension DeviceModel {
case (11, 3), (11, 4): return .iPadAir3
case (13, 1), (13, 2): return .iPadAir4
case (13, 16), (13, 17): return .iPadAir5
case (14, 8), (14, 9):
return .iPadAir11InchM2
case (14, 10), (14, 11):
return .iPadAir13InchM2
case (2, 5), (2, 6), (2, 7): return .iPadMini
case (4, 4), (4, 5), (4, 6): return .iPadMini2
case (4, 7), (4, 8), (4, 9): return .iPadMini3
Expand All @@ -227,6 +243,10 @@ extension DeviceModel {
return .iPadPro12_9Inch_FifthGen
case (14, 5), (14, 6):
return .iPadPro12_9Inch_SixthGen
case (16, 3), (16, 4):
return .iPadPro11InchM4
case (16, 5), (16, 6):
return .iPadPro13InchM4
default: return .unknown
}
}
Expand Down Expand Up @@ -281,7 +301,7 @@ extension DeviceModel {
case (6, 18): return .ultra
case (7, 1), (7, 2), (7, 3), (7, 4): return .series9
case (7, 5): return .ultra2
case (7, 8), (7, 9), (7, 10), (7, 11): return .series10
default: return .unknown
}
}
Expand Down Expand Up @@ -317,7 +337,8 @@ extension DeviceModel {
return true
case .iPhone15, .iPhone15Plus, .iPhone15Pro, .iPhone15ProMax:
return true

case .iPhone16, .iPhone16Plus, .iPhone16Pro, .iPhone16ProMax:
return true
default:
return false
}
Expand Down
83 changes: 63 additions & 20 deletions Sources/Identifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,16 @@ extension Identifier: CustomStringConvertible {
case (16, 2):
return "iPhone 15 Pro Max"

case (17, 3):
return "iPhone 16"
case (17, 4):
return "iPhone 16 Plus"
case (17, 1):
return "iPhone 16 Pro"
case (17, 2):
return "iPhone 16 Pro Max"


default:
return "unknown"
}
Expand Down Expand Up @@ -334,18 +344,20 @@ extension Identifier: CustomStringConvertible {
return "3rd Gen iPad Air (Wi-Fi)"
case (11, 4):
return "3rd Gen iPad Air (Wi-Fi+LTE)"
case (13, 1):
return "4th Gen iPad Air (Wi-Fi)"
case (13, 16):
return "5th Gen iPad Air (Wi-Fi)"
case (13, 17):
return "5th Gen iPad Air (Wi-Fi+5G)"
case (13, 2):
return "4th Gen iPad Air (Wi-Fi+LTE)"
case (11, 6):
return "8th Gen iPad (10.2 inch, WiFi)"
case (11, 7):
return "8th Gen iPad (10.2 inch, Cellular)"
case (12, 1):
return "9th Gen iPad (10.2 inch, Wi-Fi)"
case (12, 2):
return "9th Gen iPad (10.2 inch, Wi-Fi+LTE)"

case (13, 1):
return "4th Gen iPad Air (Wi-Fi)"
case (13, 2):
return "4th Gen iPad Air (Wi-Fi+LTE)"

case (13, 4):
return "3rd Gen iPad Pro (11 inch, Wi-Fi)"
case (13, 5):
Expand All @@ -354,10 +366,6 @@ extension Identifier: CustomStringConvertible {
return "3rd Gen iPad Pro (11 inch, Wi-Fi+5G)"
case (13, 7):
return "3rd Gen iPad Pro (11 inch, Wi-Fi+5G, 16GB RAM)"
case (14, 3):
return "4rd Gen iPad Pro (11 inch, Wi-Fi)"
case (14, 4):
return "4rd Gen iPad Pro (11 inch, Wi-Fi+5G)"
case (13, 8):
return "5th Gen iPad Pro (12.9 inch, Wi-Fi)"
case (13, 9):
Expand All @@ -366,22 +374,49 @@ extension Identifier: CustomStringConvertible {
return "5th Gen iPad Pro (12.9 inch, Wi-Fi+5G)"
case (13, 11):
return "5th Gen iPad Pro (12.9 inch, Wi-Fi+5G, 16GB RAM)"
case (14, 5):
return "6th Gen iPad Pro (12.9 inch, Wi-Fi)"
case (14, 6):
return "6th Gen iPad Pro (12.9 inch, Wi-Fi+5G)"
case (12, 1):
return "9th Gen iPad (10.2 inch, Wi-Fi)"
case (12, 2):
return "9th Gen iPad (10.2 inch, Wi-Fi+LTE)"

case (13, 16):
return "5th Gen iPad Air (Wi-Fi)"
case (13, 17):
return "5th Gen iPad Air (Wi-Fi+5G)"

case (13, 18):
return "10th Gen iPad (10.9 inch, Wi-Fi)"
case (13, 19):
return "10th Gen iPad (10.9 inch, Wi-Fi+5G)"

case (14, 1):
return "6th Gen iPad mini (8.3 inch, Wi-Fi)"
case (14, 2):
return "6th Gen iPad mini (8.3 inch, Wi-Fi+5G)"

case (14, 3):
return "4th Gen iPad Pro (11 inch, Wi-Fi)"
case (14, 4):
return "4th Gen iPad Pro (11 inch, Wi-Fi+5G)"
case (14, 5):
return "6th Gen iPad Pro (12.9 inch, Wi-Fi)"
case (14, 6):
return "6th Gen iPad Pro (12.9 inch, Wi-Fi+5G)"

case (14, 8):
return "iPad Air M2 (11 inch, Wi-Fi)"
case (14, 9):
return "iPad Air M2 (11 inch, Wi-Fi+5G)"
case (14, 10):
return "iPad Air M2 (13 inch, Wi-Fi)"
case (14, 11):
return "iPad Air M2 (13 inch, Wi-Fi+5G)"

case (16, 3):
return "iPad Pro M4 (11 inch, Wi-Fi)"
case (16, 4):
return "iPad Pro M4 (11 inch, Wi-Fi+5G)"
case (16, 5):
return "iPad Pro M4 (13 inch, Wi-Fi)"
case (16, 6):
return "iPad Pro M4 (13 inch, Wi-Fi+5G)"

default:
return "unknown"
}
Expand Down Expand Up @@ -477,6 +512,14 @@ extension Identifier: CustomStringConvertible {
return "Apple Watch Series 9, 45mm case (GPS + Cellular)"
case (7, 5):
return "Apple Watch Ultra 2"
case (7, 8):
return "Apple Watch Series 10, 42mm case (GPS)"
case (7, 9):
return "Apple Watch Series 10, 46mm case (GPS)"
case (7, 10):
return "Apple Watch Series 10, 42mm case (GPS + Cellular)"
case (7, 11):
return "Apple Watch Series 10, 46mm case (GPS + Cellular)"
default:
return "unknown"
}
Expand Down
41 changes: 34 additions & 7 deletions Sources/Screen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@ extension Screen {
case (1133, _): return 8.3
case (1180, _): return 10.9
case (1194, _): return 11.0
case (1210, _): return 11.0
case (1366, _): return 12.9
case (1376, _): return 13.0
default: return nil
}
}
Expand Down Expand Up @@ -104,28 +106,53 @@ extension Screen {
#if os(watchOS)
extension Screen {
public var caseSize: Int? {
switch size {
case .small(let mm):
return mm
case .medium(let mm):
return mm
case .ultra(let mm):
return mm
default:
return nil
}
}

public var size: Size? {
guard let major = identifier.version.major,
let minor = identifier.version.minor
else { return nil }

switch (major, minor) {
case (1, 1), (2, 3), (2, 6), (3, 1), (3, 3): return 38
case (1, 2), (2, 4), (2, 7), (3, 2), (3, 4): return 42
case (1, 1), (2, 3), (2, 6), (3, 1), (3, 3): return .small(mm: 38)
case (1, 2), (2, 4), (2, 7), (3, 2), (3, 4): return .medium(mm: 42)

case (4, 1), (4, 3), (5, 1), (5, 3), (5, 9),
(5, 11), (6, 1), (6, 3), (6, 10), (6, 12): return 40
(5, 11), (6, 1), (6, 3), (6, 10), (6, 12): return .small(mm: 40)
case (4, 2), (4, 4), (5, 2), (5, 4), (5, 10),
(5, 12), (6, 2), (6, 4), (6, 11), (6, 13): return 44
(5, 12), (6, 2), (6, 4), (6, 11), (6, 13): return .medium(mm: 44)

case (6, 6), (6, 8), (6, 14), (6, 16),
(7, 1), (7, 3): return 41
(7, 1), (7, 3): return .small(mm: 41)
case (6, 7), (6, 9), (6, 15), (6, 17),
(7, 2), (7, 4): return 45
(7, 2), (7, 4): return .medium(mm: 45)

case (6, 18), (7, 5): return 49
case (6, 18), (7, 5): return .ultra(mm: 49)

case (7, 8), (7, 10): return .small(mm: 42)
case (7, 9), (7, 11): return .medium(mm: 46)

default: return nil
}
}

public enum Size {
/// The smaller Apple Watch size (traditionally: 38/40/41mm)
case small(mm: Int)
/// The larger Apple Watch size (traditionally: 42/44/45mm)
case medium(mm: Int)
/// Apple Watch Ultra size
case ultra(mm: Int)
}
}
#endif
7 changes: 7 additions & 0 deletions Sources/UIDeviceExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,11 @@ public extension UIDeviceComplete where Base == DCDevice {
return Screen(width: width, height: height, scale: scale)
}
}
#elseif os(watchOS)
public extension UIDeviceComplete where Base == WKInterfaceDevice {
var screenSize: Screen? {
guard let identifier else { return nil }
return Screen(identifier: identifier)
}
}
#endif
70 changes: 60 additions & 10 deletions Tests/DeviceModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,26 @@ class DeviceModelTests: XCTestCase {
XCTAssert(deviceModel == .iPhone15ProMax , "DeviceModel - .iPhone15ProMax is failing")
}

func testDeviceModelIPhone16() {
let deviceModel = DeviceModel(identifier: Identifier("iPhone17,3"))
XCTAssert(deviceModel == .iPhone16, "DeviceModel - .iPhone16 is failing")
}

func testDeviceModelIPhone16Plus() {
let deviceModel = DeviceModel(identifier: Identifier("iPhone17,4"))
XCTAssert(deviceModel == .iPhone16Plus, "DeviceModel - .iPhone16Plus is failing")
}

func testDeviceModelIPhone16Pro() {
let deviceModel = DeviceModel(identifier: Identifier("iPhone17,1"))
XCTAssert(deviceModel == .iPhone16Pro, "DeviceModel - .iPhone16Pro is failing")
}

func testDeviceModelIPhone16ProMax() {
let deviceModel = DeviceModel(identifier: Identifier("iPhone17,2"))
XCTAssert(deviceModel == .iPhone16ProMax, "DeviceModel - .iPhone16ProMax is failing")
}

// MARK: - iPad Device Model tests

func testDeviceModelIPadFirstGen() {
Expand Down Expand Up @@ -402,15 +422,33 @@ class DeviceModelTests: XCTestCase {
let deviceModel2 = DeviceModel(identifier: Identifier("iPad8,12"))
XCTAssert(deviceModel1 == .iPadPro12_9Inch_FourthGen && deviceModel2 == .iPadPro12_9Inch_FourthGen, "DeviceModel - .iPadPro12_9Inch_FourthGen is failing")
}
func testDeviceModelIPadPro12_9Inch_FifthGen() {
let deviceModel1 = DeviceModel(identifier: Identifier("iPad13,8"))
let deviceModel2 = DeviceModel(identifier: Identifier("iPad13,9"))
let deviceModel3 = DeviceModel(identifier: Identifier("iPad13,10"))
let deviceModel4 = DeviceModel(identifier: Identifier("iPad13,11"))
XCTAssert(deviceModel1 == .iPadPro12_9Inch_FifthGen &&
deviceModel2 == .iPadPro12_9Inch_FifthGen &&
deviceModel3 == .iPadPro12_9Inch_FifthGen &&
deviceModel4 == .iPadPro12_9Inch_FifthGen, "DeviceModel - .iPadPro12_9Inch_FifthGen is failing")

func testDeviceModelIPadAir11InchM2() {
let deviceModel1 = DeviceModel(identifier: Identifier("iPad14,8"))
let deviceModel2 = DeviceModel(identifier: Identifier("iPad14,9"))
XCTAssert(deviceModel1 == .iPadAir11InchM2 &&
deviceModel2 == .iPadAir11InchM2, "DeviceModel - .iPadAir11InchM2 is failing")
}

func testDeviceModelIPadAir13InchM2() {
let deviceModel1 = DeviceModel(identifier: Identifier("iPad14,10"))
let deviceModel2 = DeviceModel(identifier: Identifier("iPad14,11"))
XCTAssert(deviceModel1 == .iPadAir13InchM2 &&
deviceModel2 == .iPadAir13InchM2, "DeviceModel - .iPadAir13InchM2 is failing")
}

func testDeviceModelIPadPro11InchM4() {
let deviceModel1 = DeviceModel(identifier: Identifier("iPad16,3"))
let deviceModel2 = DeviceModel(identifier: Identifier("iPad16,4"))
XCTAssert(deviceModel1 == .iPadPro11InchM4 &&
deviceModel2 == .iPadPro11InchM4, "DeviceModel - .iPadPro11InchM4 is failing")
}

func testDeviceModelIPadPro13InchM4() {
let deviceModel1 = DeviceModel(identifier: Identifier("iPad16,5"))
let deviceModel2 = DeviceModel(identifier: Identifier("iPad16,6"))
XCTAssert(deviceModel1 == .iPadPro13InchM4 &&
deviceModel2 == .iPadPro13InchM4, "DeviceModel - .iPadPro13InchM4 is failing")
}

func testDeviceModelIPadMini5() {
Expand Down Expand Up @@ -505,7 +543,8 @@ class DeviceModelTests: XCTestCase {

func testHasDynamicIsland() {
let withModels: [DeviceModel] = [.iPhone14Pro, .iPhone14ProMax,
.iPhone15, .iPhone15Plus, .iPhone15Pro, .iPhone15ProMax]
.iPhone15, .iPhone15Plus, .iPhone15Pro, .iPhone15ProMax,
.iPhone16, .iPhone16Plus, .iPhone16Pro, .iPhone16ProMax]

let withoutModels: [DeviceModel] = DeviceModel.allCases.filter( { !withModels.contains($0) })

Expand Down Expand Up @@ -647,5 +686,16 @@ class DeviceModelTests: XCTestCase {
XCTAssert(deviceModel == .ultra2, "DeviceModel - .ultra2 is failing")
}

func testDeviceModelWatchSeries10() {
let deviceModel1 = DeviceModel(identifier: Identifier("Watch7,8"))
let deviceModel2 = DeviceModel(identifier: Identifier("Watch7,9"))
let deviceModel3 = DeviceModel(identifier: Identifier("Watch7,10"))
let deviceModel4 = DeviceModel(identifier: Identifier("Watch7,11"))
XCTAssert(deviceModel1 == .series10, "DeviceModel - .series10 is failing")
XCTAssert(deviceModel2 == .series10, "DeviceModel - .series10 is failing")
XCTAssert(deviceModel3 == .series10, "DeviceModel - .series10 is failing")
XCTAssert(deviceModel4 == .series10, "DeviceModel - .series10 is failing")
}

#endif
}
Loading
Loading