Created
October 22, 2019 14:10
-
-
Save AmirDaliri/c09f55dcb17016f7dc60a76031c5ffe9 to your computer and use it in GitHub Desktop.
All iOS Device :)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Device.swift | |
// ISKUR | |
// | |
// Created by Amir Daliri on 10/22/19. | |
// Copyright © 2019 Mobilion. All rights reserved. | |
// | |
#if os(watchOS) | |
import WatchKit | |
#else | |
import UIKit | |
#endif | |
// MARK: - Device | |
/// This enum is a value-type wrapper and extension of | |
/// | |
/// Usage: | |
/// | |
/// let device = Device.current | |
/// | |
/// print(device) // prints, for example, "iPhone 6 Plus" | |
/// | |
/// if device == .iPhone6Plus { | |
/// // Do something | |
/// } else { | |
/// // Do something else | |
/// } | |
/// | |
/// ... | |
/// | |
/// if device.batteryState == .full || device.batteryState >= .charging(75) { | |
/// print("Your battery is happy! 😊") | |
/// } | |
/// | |
/// ... | |
/// | |
/// if device.batteryLevel >= 50 { | |
/// install_iOS() | |
/// } else { | |
/// showError() | |
/// } | |
/// | |
public enum Device { | |
#if os(iOS) | |
case iPodTouch5 | |
case iPodTouch6 | |
case iPodTouch7 | |
case iPhone4 | |
case iPhone4s | |
case iPhone5 | |
case iPhone5c | |
case iPhone5s | |
case iPhone6 | |
case iPhone6Plus | |
case iPhone6s | |
case iPhone6sPlus | |
case iPhone7 | |
case iPhone7Plus | |
case iPhoneSE | |
case iPhone8 | |
case iPhone8Plus | |
case iPhoneX | |
case iPhoneXS | |
case iPhoneXSMax | |
case iPhoneXR | |
case iPhone11 | |
case iPhone11Pro | |
case iPhone11ProMax | |
case iPad2 | |
case iPad3 | |
case iPad4 | |
case iPadAir | |
case iPadAir2 | |
case iPad5 | |
case iPad6 | |
case iPadAir3 | |
case iPad7 | |
case iPadMini | |
case iPadMini2 | |
case iPadMini3 | |
case iPadMini4 | |
case iPadMini5 | |
case iPadPro9Inch | |
case iPadPro12Inch | |
case iPadPro12Inch2 | |
case iPadPro10Inch | |
case iPadPro11Inch | |
case iPadPro12Inch3 | |
case homePod | |
#elseif os(tvOS) | |
case appleTVHD | |
case appleTV4K | |
#elseif os(watchOS) | |
case appleWatchSeries0_38mm | |
case appleWatchSeries0_42mm | |
case appleWatchSeries1_38mm | |
case appleWatchSeries1_42mm | |
case appleWatchSeries2_38mm | |
case appleWatchSeries2_42mm | |
case appleWatchSeries3_38mm | |
case appleWatchSeries3_42mm | |
case appleWatchSeries4_40mm | |
case appleWatchSeries4_44mm | |
case appleWatchSeries5_40mm | |
case appleWatchSeries5_44mm | |
#endif | |
indirect case simulator(Device) | |
case unknown(String) | |
/// Returns a `Device` representing the current device this software runs on. | |
public static var current: Device { | |
return Device.mapToDevice(identifier: Device.identifier) | |
} | |
/// Gets the identifier from the system, such as "iPhone7,1". | |
public static var identifier: String = { | |
var systemInfo = utsname() | |
uname(&systemInfo) | |
let mirror = Mirror(reflecting: systemInfo.machine) | |
let identifier = mirror.children.reduce("") { identifier, element in | |
guard let value = element.value as? Int8, value != 0 else { return identifier } | |
return identifier + String(UnicodeScalar(UInt8(value))) | |
} | |
return identifier | |
}() | |
/// Maps an identifier to a Device. If the identifier can not be mapped to an existing device, `UnknownDevice(identifier)` is returned. | |
/// | |
/// - 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 | |
#if os(iOS) | |
switch identifier { | |
case "iPod5,1": return iPodTouch5 | |
case "iPod7,1": return iPodTouch6 | |
case "iPod9,1": return iPodTouch7 | |
case "iPhone3,1", "iPhone3,2", "iPhone3,3": return iPhone4 | |
case "iPhone4,1": return iPhone4s | |
case "iPhone5,1", "iPhone5,2": return iPhone5 | |
case "iPhone5,3", "iPhone5,4": return iPhone5c | |
case "iPhone6,1", "iPhone6,2": return iPhone5s | |
case "iPhone7,2": return iPhone6 | |
case "iPhone7,1": return iPhone6Plus | |
case "iPhone8,1": return iPhone6s | |
case "iPhone8,2": return iPhone6sPlus | |
case "iPhone9,1", "iPhone9,3": return iPhone7 | |
case "iPhone9,2", "iPhone9,4": return iPhone7Plus | |
case "iPhone8,4": return iPhoneSE | |
case "iPhone10,1", "iPhone10,4": return iPhone8 | |
case "iPhone10,2", "iPhone10,5": return iPhone8Plus | |
case "iPhone10,3", "iPhone10,6": return iPhoneX | |
case "iPhone11,2": return iPhoneXS | |
case "iPhone11,4", "iPhone11,6": return iPhoneXSMax | |
case "iPhone11,8": return iPhoneXR | |
case "iPhone12,1": return iPhone11 | |
case "iPhone12,3": return iPhone11Pro | |
case "iPhone12,5": return iPhone11ProMax | |
case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4": return iPad2 | |
case "iPad3,1", "iPad3,2", "iPad3,3": return iPad3 | |
case "iPad3,4", "iPad3,5", "iPad3,6": return iPad4 | |
case "iPad4,1", "iPad4,2", "iPad4,3": return iPadAir | |
case "iPad5,3", "iPad5,4": return iPadAir2 | |
case "iPad6,11", "iPad6,12": return iPad5 | |
case "iPad7,5", "iPad7,6": return iPad6 | |
case "iPad11,3", "iPad11,4": return iPadAir3 | |
case "iPad7,11", "iPad7,12": return iPad7 | |
case "iPad2,5", "iPad2,6", "iPad2,7": return iPadMini | |
case "iPad4,4", "iPad4,5", "iPad4,6": return iPadMini2 | |
case "iPad4,7", "iPad4,8", "iPad4,9": return iPadMini3 | |
case "iPad5,1", "iPad5,2": return iPadMini4 | |
case "iPad11,1", "iPad11,2": return iPadMini5 | |
case "iPad6,3", "iPad6,4": return iPadPro9Inch | |
case "iPad6,7", "iPad6,8": return iPadPro12Inch | |
case "iPad7,1", "iPad7,2": return iPadPro12Inch2 | |
case "iPad7,3", "iPad7,4": return iPadPro10Inch | |
case "iPad8,1", "iPad8,2", "iPad8,3", "iPad8,4": return iPadPro11Inch | |
case "iPad8,5", "iPad8,6", "iPad8,7", "iPad8,8": return iPadPro12Inch3 | |
case "AudioAccessory1,1": return homePod | |
case "i386", "x86_64": return simulator(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "iOS")) | |
default: return unknown(identifier) | |
} | |
#elseif os(tvOS) | |
switch identifier { | |
case "AppleTV5,3": return appleTVHD | |
case "AppleTV6,2": return appleTV4K | |
case "i386", "x86_64": return simulator(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "tvOS")) | |
default: return unknown(identifier) | |
} | |
#elseif os(watchOS) | |
switch identifier { | |
case "Watch1,1": return appleWatchSeries0_38mm | |
case "Watch1,2": return appleWatchSeries0_42mm | |
case "Watch2,6": return appleWatchSeries1_38mm | |
case "Watch2,7": return appleWatchSeries1_42mm | |
case "Watch2,3": return appleWatchSeries2_38mm | |
case "Watch2,4": return appleWatchSeries2_42mm | |
case "Watch3,1", "Watch3,3": return appleWatchSeries3_38mm | |
case "Watch3,2", "Watch3,4": return appleWatchSeries3_42mm | |
case "Watch4,1", "Watch4,3": return appleWatchSeries4_40mm | |
case "Watch4,2", "Watch4,4": return appleWatchSeries4_44mm | |
case "Watch5,1", "Watch5,3": return appleWatchSeries5_40mm | |
case "Watch5,2", "Watch5,4": return appleWatchSeries5_44mm | |
case "i386", "x86_64": return simulator(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "watchOS")) | |
default: return unknown(identifier) | |
} | |
#endif | |
} | |
/// Get the real device from a device. | |
/// If the device is a an iPhone8Plus simulator this function returns .iPhone8Plus (the real device). | |
/// If the parameter is a real device, this function returns just that passed parameter. | |
/// | |
/// - parameter device: A device. | |
/// | |
/// - returns: the underlying device If the `device` is a `simulator`, | |
/// otherwise return the `device`. | |
public static func realDevice(from device: Device) -> Device { | |
if case let .simulator(model) = device { | |
return model | |
} | |
return device | |
} | |
#if os(iOS) || os(watchOS) | |
/// Returns diagonal screen length in inches | |
public var diagonal: Double { | |
#if os(iOS) | |
switch self { | |
case .iPodTouch5: return 4 | |
case .iPodTouch6: return 4 | |
case .iPodTouch7: return 4 | |
case .iPhone4: return 3.5 | |
case .iPhone4s: return 3.5 | |
case .iPhone5: return 4 | |
case .iPhone5c: return 4 | |
case .iPhone5s: return 4 | |
case .iPhone6: return 4.7 | |
case .iPhone6Plus: return 5.5 | |
case .iPhone6s: return 4.7 | |
case .iPhone6sPlus: return 5.5 | |
case .iPhone7: return 4.7 | |
case .iPhone7Plus: return 5.5 | |
case .iPhoneSE: return 4 | |
case .iPhone8: return 4.7 | |
case .iPhone8Plus: return 5.5 | |
case .iPhoneX: return 5.8 | |
case .iPhoneXS: return 5.8 | |
case .iPhoneXSMax: return 6.5 | |
case .iPhoneXR: return 6.1 | |
case .iPhone11: return 6.1 | |
case .iPhone11Pro: return 5.8 | |
case .iPhone11ProMax: return 6.5 | |
case .iPad2: return 9.7 | |
case .iPad3: return 9.7 | |
case .iPad4: return 9.7 | |
case .iPadAir: return 9.7 | |
case .iPadAir2: return 9.7 | |
case .iPad5: return 9.7 | |
case .iPad6: return 9.7 | |
case .iPadAir3: return 10.5 | |
case .iPad7: return 10.2 | |
case .iPadMini: return 7.9 | |
case .iPadMini2: return 7.9 | |
case .iPadMini3: return 7.9 | |
case .iPadMini4: return 7.9 | |
case .iPadMini5: return 7.9 | |
case .iPadPro9Inch: return 9.7 | |
case .iPadPro12Inch: return 12.9 | |
case .iPadPro12Inch2: return 12.9 | |
case .iPadPro10Inch: return 10.5 | |
case .iPadPro11Inch: return 11.0 | |
case .iPadPro12Inch3: return 12.9 | |
case .homePod: return -1 | |
case .simulator(let model): return model.diagonal | |
case .unknown: return -1 | |
} | |
#elseif os(watchOS) | |
switch self { | |
case .appleWatchSeries0_38mm: return 1.5 | |
case .appleWatchSeries0_42mm: return 1.6 | |
case .appleWatchSeries1_38mm: return 1.5 | |
case .appleWatchSeries1_42mm: return 1.6 | |
case .appleWatchSeries2_38mm: return 1.5 | |
case .appleWatchSeries2_42mm: return 1.6 | |
case .appleWatchSeries3_38mm: return 1.5 | |
case .appleWatchSeries3_42mm: return 1.6 | |
case .appleWatchSeries4_40mm: return 1.8 | |
case .appleWatchSeries4_44mm: return 2.0 | |
case .appleWatchSeries5_40mm: return 1.8 | |
case .appleWatchSeries5_44mm: return 2.0 | |
case .simulator(let model): return model.diagonal | |
case .unknown: return -1 | |
} | |
#endif | |
} | |
#endif | |
/// Returns screen ratio as a tuple | |
public var screenRatio: (width: Double, height: Double) { | |
#if os(iOS) | |
switch self { | |
case .iPodTouch5: return (width: 9, height: 16) | |
case .iPodTouch6: return (width: 9, height: 16) | |
case .iPodTouch7: return (width: 9, height: 16) | |
case .iPhone4: return (width: 2, height: 3) | |
case .iPhone4s: return (width: 2, height: 3) | |
case .iPhone5: return (width: 9, height: 16) | |
case .iPhone5c: return (width: 9, height: 16) | |
case .iPhone5s: return (width: 9, height: 16) | |
case .iPhone6: return (width: 9, height: 16) | |
case .iPhone6Plus: return (width: 9, height: 16) | |
case .iPhone6s: return (width: 9, height: 16) | |
case .iPhone6sPlus: return (width: 9, height: 16) | |
case .iPhone7: return (width: 9, height: 16) | |
case .iPhone7Plus: return (width: 9, height: 16) | |
case .iPhoneSE: return (width: 9, height: 16) | |
case .iPhone8: return (width: 9, height: 16) | |
case .iPhone8Plus: return (width: 9, height: 16) | |
case .iPhoneX: return (width: 9, height: 19.5) | |
case .iPhoneXS: return (width: 9, height: 19.5) | |
case .iPhoneXSMax: return (width: 9, height: 19.5) | |
case .iPhoneXR: return (width: 9, height: 19.5) | |
case .iPhone11: return (width: 9, height: 19.5) | |
case .iPhone11Pro: return (width: 9, height: 19.5) | |
case .iPhone11ProMax: return (width: 9, height: 19.5) | |
case .iPad2: return (width: 3, height: 4) | |
case .iPad3: return (width: 3, height: 4) | |
case .iPad4: return (width: 3, height: 4) | |
case .iPadAir: return (width: 3, height: 4) | |
case .iPadAir2: return (width: 3, height: 4) | |
case .iPad5: return (width: 3, height: 4) | |
case .iPad6: return (width: 3, height: 4) | |
case .iPadAir3: return (width: 3, height: 4) | |
case .iPad7: return (width: 3, height: 4) | |
case .iPadMini: return (width: 3, height: 4) | |
case .iPadMini2: return (width: 3, height: 4) | |
case .iPadMini3: return (width: 3, height: 4) | |
case .iPadMini4: return (width: 3, height: 4) | |
case .iPadMini5: return (width: 3, height: 4) | |
case .iPadPro9Inch: return (width: 3, height: 4) | |
case .iPadPro12Inch: return (width: 3, height: 4) | |
case .iPadPro12Inch2: return (width: 3, height: 4) | |
case .iPadPro10Inch: return (width: 3, height: 4) | |
case .iPadPro11Inch: return (width: 139, height: 199) | |
case .iPadPro12Inch3: return (width: 512, height: 683) | |
case .homePod: return (width: 4, height: 5) | |
case .simulator(let model): return model.screenRatio | |
case .unknown: return (width: -1, height: -1) | |
} | |
#elseif os(watchOS) | |
switch self { | |
case .appleWatchSeries0_38mm: return (width: 4, height: 5) | |
case .appleWatchSeries0_42mm: return (width: 4, height: 5) | |
case .appleWatchSeries1_38mm: return (width: 4, height: 5) | |
case .appleWatchSeries1_42mm: return (width: 4, height: 5) | |
case .appleWatchSeries2_38mm: return (width: 4, height: 5) | |
case .appleWatchSeries2_42mm: return (width: 4, height: 5) | |
case .appleWatchSeries3_38mm: return (width: 4, height: 5) | |
case .appleWatchSeries3_42mm: return (width: 4, height: 5) | |
case .appleWatchSeries4_40mm: return (width: 4, height: 5) | |
case .appleWatchSeries4_44mm: return (width: 4, height: 5) | |
case .appleWatchSeries5_40mm: return (width: 4, height: 5) | |
case .appleWatchSeries5_44mm: return (width: 4, height: 5) | |
case .simulator(let model): return model.screenRatio | |
case .unknown: return (width: -1, height: -1) | |
} | |
#elseif os(tvOS) | |
return (width: -1, height: -1) | |
#endif | |
} | |
#if os(iOS) | |
/// All iPods | |
public static var allPods: [Device] { | |
return [.iPodTouch5, .iPodTouch6, .iPodTouch7] | |
} | |
/// All iPhones | |
public static var allPhones: [Device] { | |
return [.iPhone4, .iPhone4s, .iPhone5, .iPhone5c, .iPhone5s, .iPhone6, .iPhone6Plus, .iPhone6s, .iPhone6sPlus, .iPhone7, .iPhone7Plus, .iPhoneSE, .iPhone8, .iPhone8Plus, .iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax] | |
} | |
/// All iPads | |
public static var allPads: [Device] { | |
return [.iPad2, .iPad3, .iPad4, .iPadAir, .iPadAir2, .iPad5, .iPad6, .iPadAir3, .iPad7, .iPadMini, .iPadMini2, .iPadMini3, .iPadMini4, .iPadMini5, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3] | |
} | |
/// All X-Series Devices | |
public static var allXSeriesDevices: [Device] { | |
return [.iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .simulator(.iPhoneXS), .simulator(.iPhoneXSMax), .simulator(.iPhoneXR), .iPhone11, .iPhone11Pro, .iPhone11ProMax] | |
} | |
/// All Plus-Sized Devices | |
public static var allPlusSizedDevices: [Device] { | |
return [.iPhone6Plus, .iPhone6sPlus, .iPhone7Plus, .iPhone8Plus, .simulator(.iPhone6Plus), .simulator(.iPhone6sPlus), .simulator(.iPhone7Plus), .simulator(.iPhone8Plus), .iPhoneXSMax, .iPhone11ProMax] | |
} | |
/// All Pro Devices | |
public static var allProDevices: [Device] { | |
return [.iPhone11Pro, .iPhone11ProMax, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3] | |
} | |
/// All mini Devices | |
public static var allMiniDevices: [Device] { | |
return [.iPhone5, .iPhone5s, .iPhoneSE, .iPhoneSE, .simulator(.iPhone5)] | |
// return [.iPadMini, .iPadMini2, .iPadMini3, .iPadMini4, .iPadMini5] | |
} | |
/// All normal Devices | |
public static var allNormalDevices: [Device] { | |
return [.iPhone6, .iPhone6s, .iPhone7, .iPhone8, .simulator(.iPhone6)] | |
} | |
/// All simulator iPods | |
public static var allSimulatorPods: [Device] { | |
return allPods.map(Device.simulator) | |
} | |
/// All simulator iPhones | |
public static var allSimulatorPhones: [Device] { | |
return allPhones.map(Device.simulator) | |
} | |
/// All simulator iPads | |
public static var allSimulatorPads: [Device] { | |
return allPads.map(Device.simulator) | |
} | |
/// All simulator iPad mini | |
public static var allSimulatorMiniDevices: [Device] { | |
return allMiniDevices.map(Device.simulator) | |
} | |
/// All simulator Plus-Sized Devices | |
public static var allSimulatorXSeriesDevices: [Device] { | |
return allXSeriesDevices.map(Device.simulator) | |
} | |
/// All simulator Plus-Sized Devices | |
public static var allSimulatorPlusSizedDevices: [Device] { | |
return allPlusSizedDevices.map(Device.simulator) | |
} | |
/// All simulator Pro Devices | |
public static var allSimulatorProDevices: [Device] { | |
return allProDevices.map(Device.simulator) | |
} | |
/// Returns whether the device is an iPod (real or simulator) | |
public var isPod: Bool { | |
return isOneOf(Device.allPods) || isOneOf(Device.allSimulatorPods) | |
} | |
/// Returns whether the device is an iPhone (real or simulator) | |
public var isPhone: Bool { | |
return (isOneOf(Device.allPhones) | |
|| isOneOf(Device.allSimulatorPhones) | |
|| (UIDevice.current.userInterfaceIdiom == .phone && isCurrent)) && !isPod | |
} | |
/// Returns whether the device is an iPad (real or simulator) | |
public var isPad: Bool { | |
return isOneOf(Device.allPads) | |
|| isOneOf(Device.allSimulatorPads) | |
|| (UIDevice.current.userInterfaceIdiom == .pad && isCurrent) | |
} | |
/// Returns whether the device is any of the simulator | |
/// Useful when there is a need to check and skip running a portion of code (location request or others) | |
public var isSimulator: Bool { | |
return isOneOf(Device.allSimulators) | |
} | |
/// If this device is a simulator return the underlying device, | |
/// otherwise return `self`. | |
public var realDevice: Device { | |
return Device.realDevice(from: self) | |
} | |
public var isZoomed: Bool? { | |
guard isCurrent else { return nil } | |
if Int(UIScreen.main.scale.rounded()) == 3 { | |
// Plus-sized | |
return UIScreen.main.nativeScale > 2.7 && UIScreen.main.nativeScale < 3 | |
} else { | |
return UIScreen.main.nativeScale > UIScreen.main.scale | |
} | |
} | |
/// All Touch ID Capable Devices | |
public static var allTouchIDCapableDevices: [Device] { | |
return [.iPhone5s, .iPhone6, .iPhone6Plus, .iPhone6s, .iPhone6sPlus, .iPhone7, .iPhone7Plus, .iPhoneSE, .iPhone8, .iPhone8Plus, .iPadAir2, .iPad5, .iPad6, .iPadAir3, .iPad7, .iPadMini3, .iPadMini4, .iPadMini5, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch] | |
} | |
/// All Face ID Capable Devices | |
public static var allFaceIDCapableDevices: [Device] { | |
return [.iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPadPro11Inch, .iPadPro12Inch3] | |
} | |
/// Returns whether or not the device has Touch ID | |
public var isTouchIDCapable: Bool { | |
return isOneOf(Device.allTouchIDCapableDevices) | |
} | |
/// Returns whether or not the device has Face ID | |
public var isFaceIDCapable: Bool { | |
return isOneOf(Device.allFaceIDCapableDevices) | |
} | |
/// Returns whether or not the device has any biometric sensor (i.e. Touch ID or Face ID) | |
public var hasBiometricSensor: Bool { | |
return isTouchIDCapable || isFaceIDCapable | |
} | |
/// All devices that feature a sensor housing in the screen | |
public static var allDevicesWithSensorHousing: [Device] { | |
return [.iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax] | |
} | |
/// Returns whether or not the device has a sensor housing | |
public var hasSensorHousing: Bool { | |
return isOneOf(Device.allDevicesWithSensorHousing) | |
} | |
/// All devices that feature a screen with rounded corners. | |
public static var allDevicesWithRoundedDisplayCorners: [Device] { | |
return [.iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPadPro11Inch, .iPadPro12Inch3] | |
} | |
/// Returns whether or not the device has a screen with rounded corners. | |
public var hasRoundedDisplayCorners: Bool { | |
return isOneOf(Device.allDevicesWithRoundedDisplayCorners) | |
} | |
/// All devices that have 3D Touch support. | |
public static var allDevicesWith3dTouchSupport: [Device] { | |
return [.iPhone6s, .iPhone6sPlus, .iPhone7, .iPhone7Plus, .iPhoneSE, .iPhone8, .iPhone8Plus, .iPhoneX, .iPhoneXS, .iPhoneXSMax] | |
} | |
/// Returns whether or not the device has 3D Touch support. | |
public var has3dTouchSupport: Bool { | |
return isOneOf(Device.allDevicesWith3dTouchSupport) | |
} | |
/// All devices that support wireless charging. | |
public static var allDevicesWithWirelessChargingSupport: [Device] { | |
return [.iPhone8, .iPhone8Plus, .iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax] | |
} | |
/// Returns whether or not the device supports wireless charging | |
public var supportsWirelessCharging: Bool { | |
return isOneOf(Device.allDevicesWithWirelessChargingSupport) | |
} | |
#elseif os(tvOS) | |
/// All TVs | |
public static var allTVs: [Device] { | |
return [.appleTVHD, .appleTV4K] | |
} | |
/// All simulator TVs | |
public static var allSimulatorTVs: [Device] { | |
return allTVs.map(Device.simulator) | |
} | |
#elseif os(watchOS) | |
/// All Watches | |
public static var allWatches: [Device] { | |
return [.appleWatchSeries0_38mm, .appleWatchSeries0_42mm, .appleWatchSeries1_38mm, .appleWatchSeries1_42mm, .appleWatchSeries2_38mm, .appleWatchSeries2_42mm, .appleWatchSeries3_38mm, .appleWatchSeries3_42mm, .appleWatchSeries4_40mm, .appleWatchSeries4_44mm, .appleWatchSeries5_40mm, .appleWatchSeries5_44mm] | |
} | |
/// All simulator Watches | |
public static var allSimulatorWatches: [Device] { | |
return allWatches.map(Device.simulator) | |
} | |
/// All watches that have Force Touch support. | |
public static var allWatchesWithForceTouchSupport: [Device] { | |
return [.appleWatchSeries0_38mm, .appleWatchSeries0_42mm, .appleWatchSeries1_38mm, .appleWatchSeries1_42mm, .appleWatchSeries2_38mm, .appleWatchSeries2_42mm, .appleWatchSeries3_38mm, .appleWatchSeries3_42mm, .appleWatchSeries4_40mm, .appleWatchSeries4_44mm, .appleWatchSeries5_40mm, .appleWatchSeries5_44mm] | |
} | |
/// Returns whether or not the device has Force Touch support. | |
public var hasForceTouchSupport: Bool { | |
return isOneOf(Device.allWatchesWithForceTouchSupport) | |
} | |
#endif | |
/// All real devices (i.e. all devices except for all simulators) | |
public static var allRealDevices: [Device] { | |
#if os(iOS) | |
return allPods + allPhones + allPads | |
#elseif os(tvOS) | |
return allTVs | |
#elseif os(watchOS) | |
return allWatches | |
#endif | |
} | |
/// All simulators | |
public static var allSimulators: [Device] { | |
return allRealDevices.map(Device.simulator) | |
} | |
/** | |
This method saves you in many cases from the need of updating your code with every new device. | |
Most uses for an enum like this are the following: | |
``` | |
switch Device.current { | |
case .iPodTouch5, .iPodTouch6: callMethodOnIPods() | |
case .iPhone4, iPhone4s, .iPhone5, .iPhone5s, .iPhone6, .iPhone6Plus, .iPhone6s, .iPhone6sPlus, .iPhone7, .iPhone7Plus, .iPhoneSE, .iPhone8, .iPhone8Plus, .iPhoneX: callMethodOnIPhones() | |
case .iPad2, .iPad3, .iPad4, .iPadAir, .iPadAir2, .iPadMini, .iPadMini2, .iPadMini3, .iPadMini4, .iPadPro: callMethodOnIPads() | |
default: break | |
} | |
``` | |
This code can now be replaced with | |
``` | |
let device = Device.current | |
if device.isOneOf(Device.allPods) { | |
callMethodOnIPods() | |
} else if device.isOneOf(Device.allPhones) { | |
callMethodOnIPhones() | |
} else if device.isOneOf(Device.allPads) { | |
callMethodOnIPads() | |
} | |
``` | |
- parameter devices: An array of devices. | |
- returns: Returns whether the current device is one of the passed in ones. | |
*/ | |
public func isOneOf(_ devices: [Device]) -> Bool { | |
return devices.contains(self) | |
} | |
/// Whether or not the current device is the current device. | |
private var isCurrent: Bool { | |
return self == Device.current | |
} | |
/// The name identifying the device (e.g. "Dennis' iPhone"). | |
public var name: String? { | |
guard isCurrent else { return nil } | |
#if os(watchOS) | |
return WKInterfaceDevice.current().name | |
#else | |
return UIDevice.current.name | |
#endif | |
} | |
/// The name of the operating system running on the device represented by the receiver (e.g. "iOS" or "tvOS"). | |
public var systemName: String? { | |
guard isCurrent else { return nil } | |
#if os(watchOS) | |
return WKInterfaceDevice.current().systemName | |
#else | |
return UIDevice.current.systemName | |
#endif | |
} | |
/// The current version of the operating system (e.g. 8.4 or 9.2). | |
public var systemVersion: String? { | |
guard isCurrent else { return nil } | |
#if os(watchOS) | |
return WKInterfaceDevice.current().systemVersion | |
#else | |
return UIDevice.current.systemVersion | |
#endif | |
} | |
/// The model of the device (e.g. "iPhone" or "iPod Touch"). | |
public var model: String? { | |
guard isCurrent else { return nil } | |
#if os(watchOS) | |
return WKInterfaceDevice.current().model | |
#else | |
return UIDevice.current.model | |
#endif | |
} | |
/// The model of the device as a localized string. | |
public var localizedModel: String? { | |
guard isCurrent else { return nil } | |
#if os(watchOS) | |
return WKInterfaceDevice.current().localizedModel | |
#else | |
return UIDevice.current.localizedModel | |
#endif | |
} | |
/// PPI (Pixels per Inch) on the current device's screen (if applicable). When the device is not applicable this property returns nil. | |
public var ppi: Int? { | |
#if os(iOS) | |
switch self { | |
case .iPodTouch5: return 326 | |
case .iPodTouch6: return 326 | |
case .iPodTouch7: return 326 | |
case .iPhone4: return 326 | |
case .iPhone4s: return 326 | |
case .iPhone5: return 326 | |
case .iPhone5c: return 326 | |
case .iPhone5s: return 326 | |
case .iPhone6: return 326 | |
case .iPhone6Plus: return 401 | |
case .iPhone6s: return 326 | |
case .iPhone6sPlus: return 401 | |
case .iPhone7: return 326 | |
case .iPhone7Plus: return 401 | |
case .iPhoneSE: return 326 | |
case .iPhone8: return 326 | |
case .iPhone8Plus: return 401 | |
case .iPhoneX: return 458 | |
case .iPhoneXS: return 458 | |
case .iPhoneXSMax: return 458 | |
case .iPhoneXR: return 326 | |
case .iPhone11: return 326 | |
case .iPhone11Pro: return 458 | |
case .iPhone11ProMax: return 458 | |
case .iPad2: return 132 | |
case .iPad3: return 264 | |
case .iPad4: return 264 | |
case .iPadAir: return 264 | |
case .iPadAir2: return 264 | |
case .iPad5: return 264 | |
case .iPad6: return 264 | |
case .iPadAir3: return 264 | |
case .iPad7: return 264 | |
case .iPadMini: return 163 | |
case .iPadMini2: return 326 | |
case .iPadMini3: return 326 | |
case .iPadMini4: return 326 | |
case .iPadMini5: return 326 | |
case .iPadPro9Inch: return 264 | |
case .iPadPro12Inch: return 264 | |
case .iPadPro12Inch2: return 264 | |
case .iPadPro10Inch: return 264 | |
case .iPadPro11Inch: return 264 | |
case .iPadPro12Inch3: return 264 | |
case .homePod: return -1 | |
case .simulator(let model): return model.ppi | |
case .unknown: return nil | |
} | |
#elseif os(watchOS) | |
switch self { | |
case .appleWatchSeries0_38mm: return 290 | |
case .appleWatchSeries0_42mm: return 303 | |
case .appleWatchSeries1_38mm: return 290 | |
case .appleWatchSeries1_42mm: return 303 | |
case .appleWatchSeries2_38mm: return 290 | |
case .appleWatchSeries2_42mm: return 303 | |
case .appleWatchSeries3_38mm: return 290 | |
case .appleWatchSeries3_42mm: return 303 | |
case .appleWatchSeries4_40mm: return 326 | |
case .appleWatchSeries4_44mm: return 326 | |
case .appleWatchSeries5_40mm: return 326 | |
case .appleWatchSeries5_44mm: return 326 | |
case .simulator(let model): return model.ppi | |
case .unknown: return nil | |
} | |
#elseif os(tvOS) | |
return nil | |
#endif | |
} | |
/// True when a Guided Access session is currently active; otherwise, false. | |
public var isGuidedAccessSessionActive: Bool { | |
#if os(iOS) | |
#if swift(>=4.2) | |
return UIAccessibility.isGuidedAccessEnabled | |
#else | |
return UIAccessibilityIsGuidedAccessEnabled() | |
#endif | |
#else | |
return false | |
#endif | |
} | |
/// The brightness level of the screen. | |
public var screenBrightness: Int { | |
#if os(iOS) | |
return Int(UIScreen.main.brightness * 100) | |
#else | |
return 100 | |
#endif | |
} | |
} | |
// MARK: - CustomStringConvertible | |
extension Device: CustomStringConvertible { | |
/// A textual representation of the device. | |
public var description: String { | |
#if os(iOS) | |
switch self { | |
case .iPodTouch5: return "iPod touch (5th generation)" | |
case .iPodTouch6: return "iPod touch (6th generation)" | |
case .iPodTouch7: return "iPod touch (7th generation)" | |
case .iPhone4: return "iPhone 4" | |
case .iPhone4s: return "iPhone 4s" | |
case .iPhone5: return "iPhone 5" | |
case .iPhone5c: return "iPhone 5c" | |
case .iPhone5s: return "iPhone 5s" | |
case .iPhone6: return "iPhone 6" | |
case .iPhone6Plus: return "iPhone 6 Plus" | |
case .iPhone6s: return "iPhone 6s" | |
case .iPhone6sPlus: return "iPhone 6s Plus" | |
case .iPhone7: return "iPhone 7" | |
case .iPhone7Plus: return "iPhone 7 Plus" | |
case .iPhoneSE: return "iPhone SE" | |
case .iPhone8: return "iPhone 8" | |
case .iPhone8Plus: return "iPhone 8 Plus" | |
case .iPhoneX: return "iPhone X" | |
case .iPhoneXS: return "iPhone Xs" | |
case .iPhoneXSMax: return "iPhone Xs Max" | |
case .iPhoneXR: return "iPhone Xʀ" | |
case .iPhone11: return "iPhone 11" | |
case .iPhone11Pro: return "iPhone 11 Pro" | |
case .iPhone11ProMax: return "iPhone 11 Pro Max" | |
case .iPad2: return "iPad 2" | |
case .iPad3: return "iPad (3rd generation)" | |
case .iPad4: return "iPad (4th generation)" | |
case .iPadAir: return "iPad Air" | |
case .iPadAir2: return "iPad Air 2" | |
case .iPad5: return "iPad (5th generation)" | |
case .iPad6: return "iPad (6th generation)" | |
case .iPadAir3: return "iPad Air (3rd generation)" | |
case .iPad7: return "iPad (7th generation)" | |
case .iPadMini: return "iPad Mini" | |
case .iPadMini2: return "iPad Mini 2" | |
case .iPadMini3: return "iPad Mini 3" | |
case .iPadMini4: return "iPad Mini 4" | |
case .iPadMini5: return "iPad Mini (5th generation)" | |
case .iPadPro9Inch: return "iPad Pro (9.7-inch)" | |
case .iPadPro12Inch: return "iPad Pro (12.9-inch)" | |
case .iPadPro12Inch2: return "iPad Pro (12.9-inch) (2nd generation)" | |
case .iPadPro10Inch: return "iPad Pro (10.5-inch)" | |
case .iPadPro11Inch: return "iPad Pro (11-inch)" | |
case .iPadPro12Inch3: return "iPad Pro (12.9-inch) (3rd generation)" | |
case .homePod: return "HomePod" | |
case .simulator(let model): return "Simulator (\(model))" | |
case .unknown(let identifier): return identifier | |
} | |
#elseif os(watchOS) | |
switch self { | |
case .appleWatchSeries0_38mm: return "Apple Watch (1st generation) 38mm" | |
case .appleWatchSeries0_42mm: return "Apple Watch (1st generation) 42mm" | |
case .appleWatchSeries1_38mm: return "Apple Watch Series 1 38mm" | |
case .appleWatchSeries1_42mm: return "Apple Watch Series 1 42mm" | |
case .appleWatchSeries2_38mm: return "Apple Watch Series 2 38mm" | |
case .appleWatchSeries2_42mm: return "Apple Watch Series 2 42mm" | |
case .appleWatchSeries3_38mm: return "Apple Watch Series 3 38mm" | |
case .appleWatchSeries3_42mm: return "Apple Watch Series 3 42mm" | |
case .appleWatchSeries4_40mm: return "Apple Watch Series 4 40mm" | |
case .appleWatchSeries4_44mm: return "Apple Watch Series 4 44mm" | |
case .appleWatchSeries5_40mm: return "Apple Watch Series 5 40mm" | |
case .appleWatchSeries5_44mm: return "Apple Watch Series 5 44mm" | |
case .simulator(let model): return "Simulator (\(model))" | |
case .unknown(let identifier): return identifier | |
} | |
#elseif os(tvOS) | |
switch self { | |
case .appleTVHD: return "Apple TV HD" | |
case .appleTV4K: return "Apple TV 4K" | |
case .simulator(let model): return "Simulator (\(model))" | |
case .unknown(let identifier): return identifier | |
} | |
#endif | |
} | |
} | |
// MARK: - Equatable | |
extension Device: Equatable { | |
/// Compares two devices | |
/// | |
/// - parameter lhs: A device. | |
/// - parameter rhs: Another device. | |
/// | |
/// - returns: `true` iff the underlying identifier is the same. | |
public static func == (lhs: Device, rhs: Device) -> Bool { | |
return lhs.description == rhs.description | |
} | |
} | |
// MARK: - Battery | |
#if os(iOS) || os(watchOS) | |
@available(iOS 8.0, watchOS 4.0, *) | |
extension Device { | |
/** | |
This enum describes the state of the battery. | |
- Full: The device is plugged into power and the battery is 100% charged or the device is the iOS Simulator. | |
- Charging: The device is plugged into power and the battery is less than 100% charged. | |
- Unplugged: The device is not plugged into power; the battery is discharging. | |
*/ | |
public enum BatteryState: CustomStringConvertible, Equatable { | |
/// The device is plugged into power and the battery is 100% charged or the device is the iOS Simulator. | |
case full | |
/// The device is plugged into power and the battery is less than 100% charged. | |
/// The associated value is in percent (0-100). | |
case charging(Int) | |
/// The device is not plugged into power; the battery is discharging. | |
/// The associated value is in percent (0-100). | |
case unplugged(Int) | |
#if os(iOS) | |
fileprivate init() { | |
let wasBatteryMonitoringEnabled = UIDevice.current.isBatteryMonitoringEnabled | |
UIDevice.current.isBatteryMonitoringEnabled = true | |
let batteryLevel = Int(round(UIDevice.current.batteryLevel * 100)) // round() is actually not needed anymore since -[batteryLevel] seems to always return a two-digit precision number | |
// but maybe that changes in the future. | |
switch UIDevice.current.batteryState { | |
case .charging: self = .charging(batteryLevel) | |
case .full: self = .full | |
case .unplugged: self = .unplugged(batteryLevel) | |
case .unknown: self = .full // Should never happen since `batteryMonitoring` is enabled. | |
@unknown default: | |
self = .full // To cover any future additions for which DeviceKit might not have updated yet. | |
} | |
UIDevice.current.isBatteryMonitoringEnabled = wasBatteryMonitoringEnabled | |
} | |
#elseif os(watchOS) | |
fileprivate init() { | |
let wasBatteryMonitoringEnabled = WKInterfaceDevice.current().isBatteryMonitoringEnabled | |
WKInterfaceDevice.current().isBatteryMonitoringEnabled = true | |
let batteryLevel = Int(round(WKInterfaceDevice.current().batteryLevel * 100)) // round() is actually not needed anymore since -[batteryLevel] seems to always return a two-digit precision number | |
// but maybe that changes in the future. | |
switch WKInterfaceDevice.current().batteryState { | |
case .charging: self = .charging(batteryLevel) | |
case .full: self = .full | |
case .unplugged: self = .unplugged(batteryLevel) | |
case .unknown: self = .full // Should never happen since `batteryMonitoring` is enabled. | |
@unknown default: | |
self = .full // To cover any future additions for which DeviceKit might not have updated yet. | |
} | |
WKInterfaceDevice.current().isBatteryMonitoringEnabled = wasBatteryMonitoringEnabled | |
} | |
#endif | |
/// The user enabled Low Power mode | |
public var lowPowerMode: Bool { | |
return false | |
} | |
/// Provides a textual representation of the battery state. | |
/// Examples: | |
/// ``` | |
/// Battery level: 90%, device is plugged in. | |
/// Battery level: 100 % (Full), device is plugged in. | |
/// Battery level: \(batteryLevel)%, device is unplugged. | |
/// ``` | |
public var description: String { | |
switch self { | |
case .charging(let batteryLevel): return "Battery level: \(batteryLevel)%, device is plugged in." | |
case .full: return "Battery level: 100 % (Full), device is plugged in." | |
case .unplugged(let batteryLevel): return "Battery level: \(batteryLevel)%, device is unplugged." | |
} | |
} | |
} | |
/// The state of the battery | |
public var batteryState: BatteryState? { | |
guard isCurrent else { return nil } | |
return BatteryState() | |
} | |
/// Battery level ranges from 0 (fully discharged) to 100 (100% charged). | |
public var batteryLevel: Int? { | |
guard isCurrent else { return nil } | |
switch BatteryState() { | |
case .charging(let value): return value | |
case .full: return 100 | |
case .unplugged(let value): return value | |
} | |
} | |
} | |
#endif | |
// MARK: - Device.Batterystate: Comparable | |
#if os(iOS) || os(watchOS) | |
@available(iOS 8.0, watchOS 4.0, *) | |
extension Device.BatteryState: Comparable { | |
/// Tells if two battery states are equal. | |
/// | |
/// - parameter lhs: A battery state. | |
/// - parameter rhs: Another battery state. | |
/// | |
/// - returns: `true` iff they are equal, otherwise `false` | |
public static func == (lhs: Device.BatteryState, rhs: Device.BatteryState) -> Bool { | |
return lhs.description == rhs.description | |
} | |
/// Compares two battery states. | |
/// | |
/// - parameter lhs: A battery state. | |
/// - parameter rhs: Another battery state. | |
/// | |
/// - returns: `true` if rhs is `.Full`, `false` when lhs is `.Full` otherwise their battery level is compared. | |
public static func < (lhs: Device.BatteryState, rhs: Device.BatteryState) -> Bool { | |
switch (lhs, rhs) { | |
case (.full, _): return false // return false (even if both are `.Full` -> they are equal) | |
case (_, .full): return true // lhs is *not* `.Full`, rhs is | |
case let (.charging(lhsLevel), .charging(rhsLevel)): return lhsLevel < rhsLevel | |
case let (.charging(lhsLevel), .unplugged(rhsLevel)): return lhsLevel < rhsLevel | |
case let (.unplugged(lhsLevel), .charging(rhsLevel)): return lhsLevel < rhsLevel | |
case let (.unplugged(lhsLevel), .unplugged(rhsLevel)): return lhsLevel < rhsLevel | |
default: return false // compiler won't compile without it, though it cannot happen | |
} | |
} | |
} | |
#endif | |
#if os(iOS) | |
extension Device { | |
// MARK: - Orientation | |
/** | |
This enum describes the state of the orientation. | |
- Landscape: The device is in Landscape Orientation | |
- Portrait: The device is in Portrait Orientation | |
*/ | |
public enum Orientation { | |
case landscape | |
case portrait | |
} | |
public var orientation: Orientation { | |
if UIDevice.current.orientation.isLandscape { | |
return .landscape | |
} else { | |
return .portrait | |
} | |
} | |
} | |
#endif | |
#if os(iOS) | |
// MARK: - DiskSpace | |
extension Device { | |
/// Return the root url | |
/// | |
/// - returns: the NSHomeDirectory() url | |
private static let rootURL = URL(fileURLWithPath: NSHomeDirectory()) | |
/// The volume’s total capacity in bytes. | |
public static var volumeTotalCapacity: Int? { | |
return (try? Device.rootURL.resourceValues(forKeys: [.volumeTotalCapacityKey]))?.volumeTotalCapacity | |
} | |
/// The volume’s available capacity in bytes. | |
public static var volumeAvailableCapacity: Int? { | |
return (try? rootURL.resourceValues(forKeys: [.volumeAvailableCapacityKey]))?.volumeAvailableCapacity | |
} | |
/// The volume’s available capacity in bytes for storing important resources. | |
@available(iOS 11.0, *) | |
public static var volumeAvailableCapacityForImportantUsage: Int64? { | |
return (try? rootURL.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey]))?.volumeAvailableCapacityForImportantUsage | |
} | |
/// 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 | |
return (try? rootURL.resourceValues(forKeys: [.volumeAvailableCapacityForOpportunisticUsageKey]))?.volumeAvailableCapacityForOpportunisticUsage | |
} | |
/// All volumes capacity information in bytes. | |
@available(iOS 11.0, *) | |
public static var volumes: [URLResourceKey: Int64]? { | |
do { | |
let values = try rootURL.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey, | |
.volumeAvailableCapacityKey, | |
.volumeAvailableCapacityForOpportunisticUsageKey, | |
.volumeTotalCapacityKey | |
]) | |
return values.allValues.mapValues { | |
if let int = $0 as? Int64 { | |
return int | |
} | |
if let int = $0 as? Int { | |
return Int64(int) | |
} | |
return 0 | |
} | |
} catch { | |
return nil | |
} | |
} | |
} | |
#endif | |
#if os(iOS) | |
// MARK: - Apple Pencil | |
extension Device { | |
/** | |
This option set describes the current Apple Pencils | |
- firstGeneration: 1st Generation Apple Pencil | |
- secondGeneration: 2nd Generation Apple Pencil | |
*/ | |
public struct ApplePencilSupport: OptionSet { | |
public var rawValue: UInt | |
public init(rawValue: UInt) { | |
self.rawValue = rawValue | |
} | |
public static let firstGeneration = ApplePencilSupport(rawValue: 0x01) | |
public static let secondGeneration = ApplePencilSupport(rawValue: 0x02) | |
} | |
/// All Apple Pencil Capable Devices | |
public static var allApplePencilCapableDevices: [Device] { | |
return [.iPad6, .iPadAir3, .iPad7, .iPadMini5, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3] | |
} | |
/// Returns supported version of the Apple Pencil | |
public var applePencilSupport: ApplePencilSupport { | |
switch self { | |
case .iPad6: return .firstGeneration | |
case .iPadAir3: return .firstGeneration | |
case .iPad7: return .firstGeneration | |
case .iPadMini5: return .firstGeneration | |
case .iPadPro9Inch: return .firstGeneration | |
case .iPadPro12Inch: return .firstGeneration | |
case .iPadPro12Inch2: return .firstGeneration | |
case .iPadPro10Inch: return .firstGeneration | |
case .iPadPro11Inch: return .secondGeneration | |
case .iPadPro12Inch3: return .secondGeneration | |
default: return [] | |
} | |
} | |
} | |
#endif | |
#if os(iOS) | |
// MARK: - Cameras | |
extension Device { | |
public enum CameraTypes { | |
case normal | |
case telephoto | |
case ultraWide | |
} | |
/// Returns an array of the types of cameras the device has | |
public var cameras: [CameraTypes] { | |
switch self { | |
case .iPodTouch5: return [.normal] | |
case .iPodTouch6: return [.normal] | |
case .iPodTouch7: return [.normal] | |
case .iPhone4: return [.normal] | |
case .iPhone4s: return [.normal] | |
case .iPhone5: return [.normal] | |
case .iPhone5c: return [.normal] | |
case .iPhone5s: return [.normal] | |
case .iPhone6: return [.normal] | |
case .iPhone6Plus: return [.normal] | |
case .iPhone6s: return [.normal] | |
case .iPhone6sPlus: return [.normal] | |
case .iPhone7: return [.normal] | |
case .iPhoneSE: return [.normal] | |
case .iPhone8: return [.normal] | |
case .iPhoneXR: return [.normal] | |
case .iPad2: return [.normal] | |
case .iPad3: return [.normal] | |
case .iPad4: return [.normal] | |
case .iPadAir: return [.normal] | |
case .iPadAir2: return [.normal] | |
case .iPad5: return [.normal] | |
case .iPad6: return [.normal] | |
case .iPadAir3: return [.normal] | |
case .iPad7: return [.normal] | |
case .iPadMini: return [.normal] | |
case .iPadMini2: return [.normal] | |
case .iPadMini3: return [.normal] | |
case .iPadMini4: return [.normal] | |
case .iPadMini5: return [.normal] | |
case .iPadPro9Inch: return [.normal] | |
case .iPadPro12Inch: return [.normal] | |
case .iPadPro12Inch2: return [.normal] | |
case .iPadPro10Inch: return [.normal] | |
case .iPadPro11Inch: return [.normal] | |
case .iPadPro12Inch3: return [.normal] | |
case .iPhone7Plus: return [.normal, .telephoto] | |
case .iPhone8Plus: return [.normal, .telephoto] | |
case .iPhoneX: return [.normal, .telephoto] | |
case .iPhoneXS: return [.normal, .telephoto] | |
case .iPhoneXSMax: return [.normal, .telephoto] | |
case .iPhone11: return [.normal, .ultraWide] | |
case .iPhone11Pro: return [.normal, .telephoto, .ultraWide] | |
case .iPhone11ProMax: return [.normal, .telephoto, .ultraWide] | |
default: return [] | |
} | |
} | |
/// All devices that feature a camera | |
public static var allDevicesWithCamera: [Device] { | |
return [.iPodTouch5, .iPodTouch6, .iPodTouch7, .iPhone4, .iPhone4s, .iPhone5, .iPhone5c, .iPhone5s, .iPhone6, .iPhone6Plus, .iPhone6s, .iPhone6sPlus, .iPhone7, .iPhone7Plus, .iPhoneSE, .iPhone8, .iPhone8Plus, .iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPad2, .iPad3, .iPad4, .iPadAir, .iPadAir2, .iPad5, .iPad6, .iPadAir3, .iPad7, .iPadMini, .iPadMini2, .iPadMini3, .iPadMini4, .iPadMini5, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3] | |
} | |
/// All devices that feature a normal camera | |
public static var allDevicesWithNormalCamera: [Device] { | |
return [.iPodTouch5, .iPodTouch6, .iPodTouch7, .iPhone4, .iPhone4s, .iPhone5, .iPhone5c, .iPhone5s, .iPhone6, .iPhone6Plus, .iPhone6s, .iPhone6sPlus, .iPhone7, .iPhone7Plus, .iPhoneSE, .iPhone8, .iPhone8Plus, .iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPad2, .iPad3, .iPad4, .iPadAir, .iPadAir2, .iPad5, .iPad6, .iPadAir3, .iPad7, .iPadMini, .iPadMini2, .iPadMini3, .iPadMini4, .iPadMini5, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3] | |
} | |
/// All devices that feature a telephoto camera | |
public static var allDevicesWithTelephotoCamera: [Device] { | |
return [.iPhone7Plus, .iPhone8Plus, .iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhone11Pro, .iPhone11ProMax] | |
} | |
/// All devices that feature an ultra wide camera | |
public static var allDevicesWithUltraWideCamera: [Device] { | |
return [.iPhone11, .iPhone11Pro, .iPhone11ProMax] | |
} | |
/// Returns whether or not the current device has a camera | |
public var hasCamera: Bool { | |
return !self.cameras.isEmpty | |
} | |
/// Returns whether or not the current device has a normal camera | |
public var hasNormalCamera: Bool { | |
return self.cameras.contains(.normal) | |
} | |
/// Returns whether or not the current device has a telephoto camera | |
public var hasTelephotoCamera: Bool { | |
return self.cameras.contains(.telephoto) | |
} | |
/// Returns whether or not the current device has an ultra wide camera | |
public var hasUltraWideCamera: Bool { | |
return self.cameras.contains(.ultraWide) | |
} | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment