Device.generated.swift 72 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694
  1. //===----------------------------------------------------------------------===//
  2. //
  3. // This source file is part of the DeviceKit open source project
  4. //
  5. // Copyright © 2014 - 2018 Dennis Weissmann and the DeviceKit project authors
  6. //
  7. // License: https://github.com/dennisweissmann/DeviceKit/blob/master/LICENSE
  8. // Contributors: https://github.com/dennisweissmann/DeviceKit#contributors
  9. //
  10. //===----------------------------------------------------------------------===//
  11. #if os(watchOS)
  12. import WatchKit
  13. #else
  14. import UIKit
  15. #endif
  16. // MARK: Device
  17. /// This enum is a value-type wrapper and extension of
  18. /// [`UIDevice`](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIDevice_Class/).
  19. ///
  20. /// Usage:
  21. ///
  22. /// let device = Device.current
  23. ///
  24. /// print(device) // prints, for example, "iPhone 6 Plus"
  25. ///
  26. /// if device == .iPhone6Plus {
  27. /// // Do something
  28. /// } else {
  29. /// // Do something else
  30. /// }
  31. ///
  32. /// ...
  33. ///
  34. /// if device.batteryState == .full || device.batteryState >= .charging(75) {
  35. /// print("Your battery is happy! 😊")
  36. /// }
  37. ///
  38. /// ...
  39. ///
  40. /// if device.batteryLevel >= 50 {
  41. /// install_iOS()
  42. /// } else {
  43. /// showError()
  44. /// }
  45. ///
  46. public enum Device {
  47. #if os(iOS)
  48. /// Device is an [iPod touch (5th generation)](https://support.apple.com/kb/SP657)
  49. ///
  50. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP657/sp657_ipod-touch_size.jpg)
  51. case iPodTouch5
  52. /// Device is an [iPod touch (6th generation)](https://support.apple.com/kb/SP720)
  53. ///
  54. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP720/SP720-ipod-touch-specs-color-sg-2015.jpg)
  55. case iPodTouch6
  56. /// Device is an [iPod touch (7th generation)](https://support.apple.com/kb/SP796)
  57. ///
  58. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP796/ipod-touch-7th-gen_2x.png)
  59. case iPodTouch7
  60. /// Device is an [iPhone 4](https://support.apple.com/kb/SP587)
  61. ///
  62. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP643/sp643_iphone4s_color_black.jpg)
  63. case iPhone4
  64. /// Device is an [iPhone 4s](https://support.apple.com/kb/SP643)
  65. ///
  66. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP643/sp643_iphone4s_color_black.jpg)
  67. case iPhone4s
  68. /// Device is an [iPhone 5](https://support.apple.com/kb/SP655)
  69. ///
  70. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP655/sp655_iphone5_color.jpg)
  71. case iPhone5
  72. /// Device is an [iPhone 5c](https://support.apple.com/kb/SP684)
  73. ///
  74. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP684/SP684-color_yellow.jpg)
  75. case iPhone5c
  76. /// Device is an [iPhone 5s](https://support.apple.com/kb/SP685)
  77. ///
  78. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP685/SP685-color_black.jpg)
  79. case iPhone5s
  80. /// Device is an [iPhone 6](https://support.apple.com/kb/SP705)
  81. ///
  82. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP705/SP705-iphone_6-mul.png)
  83. case iPhone6
  84. /// Device is an [iPhone 6 Plus](https://support.apple.com/kb/SP706)
  85. ///
  86. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP706/SP706-iphone_6_plus-mul.png)
  87. case iPhone6Plus
  88. /// Device is an [iPhone 6s](https://support.apple.com/kb/SP726)
  89. ///
  90. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP726/SP726-iphone6s-gray-select-2015.png)
  91. case iPhone6s
  92. /// Device is an [iPhone 6s Plus](https://support.apple.com/kb/SP727)
  93. ///
  94. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP727/SP727-iphone6s-plus-gray-select-2015.png)
  95. case iPhone6sPlus
  96. /// Device is an [iPhone 7](https://support.apple.com/kb/SP743)
  97. ///
  98. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP743/iphone7-black.png)
  99. case iPhone7
  100. /// Device is an [iPhone 7 Plus](https://support.apple.com/kb/SP744)
  101. ///
  102. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP744/iphone7-plus-black.png)
  103. case iPhone7Plus
  104. /// Device is an [iPhone SE](https://support.apple.com/kb/SP738)
  105. ///
  106. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP738/SP738.png)
  107. case iPhoneSE
  108. /// Device is an [iPhone 8](https://support.apple.com/kb/SP767)
  109. ///
  110. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP767/iphone8.png)
  111. case iPhone8
  112. /// Device is an [iPhone 8 Plus](https://support.apple.com/kb/SP768)
  113. ///
  114. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP768/iphone8plus.png)
  115. case iPhone8Plus
  116. /// Device is an [iPhone X](https://support.apple.com/kb/SP770)
  117. ///
  118. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP770/iphonex.png)
  119. case iPhoneX
  120. /// Device is an [iPhone Xs](https://support.apple.com/kb/SP779)
  121. ///
  122. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP779/SP779-iphone-xs.jpg)
  123. case iPhoneXS
  124. /// Device is an [iPhone Xs Max](https://support.apple.com/kb/SP780)
  125. ///
  126. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP780/SP780-iPhone-Xs-Max.jpg)
  127. case iPhoneXSMax
  128. /// Device is an [iPhone Xʀ](https://support.apple.com/kb/SP781)
  129. ///
  130. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP781/SP781-iPhone-xr.jpg)
  131. case iPhoneXR
  132. /// Device is an [iPhone 11](https://support.apple.com/kb/SP804)
  133. ///
  134. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP804/sp804-iphone11_2x.png)
  135. case iPhone11
  136. /// Device is an [iPhone 11 Pro](https://support.apple.com/kb/SP805)
  137. ///
  138. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP805/sp805-iphone11pro_2x.png)
  139. case iPhone11Pro
  140. /// Device is an [iPhone 11 Pro Max](https://support.apple.com/kb/SP806)
  141. ///
  142. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP806/sp806-iphone11pro-max_2x.png)
  143. case iPhone11ProMax
  144. /// Device is an [iPhone SE (2nd generation)](https://support.apple.com/kb/SP820)
  145. ///
  146. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP820/iphone-se-2nd-gen_2x.png)
  147. case iPhoneSE2
  148. /// Device is an [iPhone 12](TODO)
  149. ///
  150. /// ![Image](TODO)
  151. case iPhone12
  152. /// Device is an [iPhone 12 mini](TODO)
  153. ///
  154. /// ![Image](TODO)
  155. case iPhone12Mini
  156. /// Device is an [iPhone 12 Pro](TODO)
  157. ///
  158. /// ![Image](TODO)
  159. case iPhone12Pro
  160. /// Device is an [iPhone 12 Pro Max](TODO)
  161. ///
  162. /// ![Image](TODO)
  163. case iPhone12ProMax
  164. /// Device is an [iPad 2](https://support.apple.com/kb/SP622)
  165. ///
  166. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP622/SP622_01-ipad2-mul.png)
  167. case iPad2
  168. /// Device is an [iPad (3rd generation)](https://support.apple.com/kb/SP647)
  169. ///
  170. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP662/sp662_ipad-4th-gen_color.jpg)
  171. case iPad3
  172. /// Device is an [iPad (4th generation)](https://support.apple.com/kb/SP662)
  173. ///
  174. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP662/sp662_ipad-4th-gen_color.jpg)
  175. case iPad4
  176. /// Device is an [iPad Air](https://support.apple.com/kb/SP692)
  177. ///
  178. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP692/SP692-specs_color-mul.png)
  179. case iPadAir
  180. /// Device is an [iPad Air 2](https://support.apple.com/kb/SP708)
  181. ///
  182. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP708/SP708-space_gray.jpeg)
  183. case iPadAir2
  184. /// Device is an [iPad (5th generation)](https://support.apple.com/kb/SP751)
  185. ///
  186. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP751/ipad_5th_generation.png)
  187. case iPad5
  188. /// Device is an [iPad (6th generation)](https://support.apple.com/kb/SP774)
  189. ///
  190. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP774/sp774-ipad-6-gen_2x.png)
  191. case iPad6
  192. /// Device is an [iPad Air (3rd generation)](https://support.apple.com/kb/SP787)
  193. ///
  194. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP787/ipad-air-2019.jpg)
  195. case iPadAir3
  196. /// Device is an [iPad (7th generation)](https://support.apple.com/kb/SP807)
  197. ///
  198. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP807/sp807-ipad-7th-gen_2x.png)
  199. case iPad7
  200. /// Device is an [iPad (8th generation)](https://support.apple.com/kb/SP822)
  201. ///
  202. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP822/sp822-ipad-8gen_2x.png)
  203. case iPad8
  204. /// Device is an [iPad Air (4th generation)](TODO)
  205. ///
  206. /// ![Image](TODO)
  207. case iPadAir4
  208. /// Device is an [iPad Mini](https://support.apple.com/kb/SP661)
  209. ///
  210. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP661/sp661_ipad_mini_color.jpg)
  211. case iPadMini
  212. /// Device is an [iPad Mini 2](https://support.apple.com/kb/SP693)
  213. ///
  214. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP693/SP693-specs_color-mul.png)
  215. case iPadMini2
  216. /// Device is an [iPad Mini 3](https://support.apple.com/kb/SP709)
  217. ///
  218. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP709/SP709-space_gray.jpeg)
  219. case iPadMini3
  220. /// Device is an [iPad Mini 4](https://support.apple.com/kb/SP725)
  221. ///
  222. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP725/SP725ipad-mini-4.png)
  223. case iPadMini4
  224. /// Device is an [iPad Mini (5th generation)](https://support.apple.com/kb/SP788)
  225. ///
  226. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP788/ipad-mini-2019.jpg)
  227. case iPadMini5
  228. /// Device is an [iPad Pro 9.7-inch](https://support.apple.com/kb/SP739)
  229. ///
  230. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP739/SP739.png)
  231. case iPadPro9Inch
  232. /// Device is an [iPad Pro 12-inch](https://support.apple.com/kb/SP723)
  233. ///
  234. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP723/SP723-iPad_Pro_2x.png)
  235. case iPadPro12Inch
  236. /// Device is an [iPad Pro 12-inch (2nd generation)](https://support.apple.com/kb/SP761)
  237. ///
  238. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP761/ipad-pro-12in-hero-201706.png)
  239. case iPadPro12Inch2
  240. /// Device is an [iPad Pro 10.5-inch](https://support.apple.com/kb/SP762)
  241. ///
  242. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP761/ipad-pro-10in-hero-201706.png)
  243. case iPadPro10Inch
  244. /// Device is an [iPad Pro 11-inch](https://support.apple.com/kb/SP784)
  245. ///
  246. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP784/ipad-pro-11-2018_2x.png)
  247. case iPadPro11Inch
  248. /// Device is an [iPad Pro 12.9-inch (3rd generation)](https://support.apple.com/kb/SP785)
  249. ///
  250. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP785/ipad-pro-12-2018_2x.png)
  251. case iPadPro12Inch3
  252. /// Device is an [iPad Pro 11-inch (2nd generation)](https://support.apple.com/kb/SP814)
  253. ///
  254. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP814/ipad-pro-11-2020.jpeg)
  255. case iPadPro11Inch2
  256. /// Device is an [iPad Pro 12.9-inch (4th generation)](https://support.apple.com/kb/SP815)
  257. ///
  258. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP815/ipad-pro-12-2020.jpeg)
  259. case iPadPro12Inch4
  260. /// Device is a [HomePod](https://support.apple.com/kb/SP773)
  261. ///
  262. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP773/homepod_space_gray_large_2x.jpg)
  263. case homePod
  264. #elseif os(tvOS)
  265. /// Device is an [Apple TV HD](https://support.apple.com/kb/SP724) (Previously Apple TV (4th generation))
  266. ///
  267. /// ![Image](http://images.apple.com/v/tv/c/images/overview/buy_tv_large_2x.jpg)
  268. case appleTVHD
  269. /// Device is an [Apple TV 4K](https://support.apple.com/kb/SP769)
  270. ///
  271. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP769/appletv4k.png)
  272. case appleTV4K
  273. #elseif os(watchOS)
  274. /// Device is an [Apple Watch (1st generation)](https://support.apple.com/kb/SP735)
  275. ///
  276. /// ![Image](https://km.support.apple.com/resources/sites/APPLE/content/live/IMAGES/0/IM784/en_US/apple_watch_sport-240.png)
  277. case appleWatchSeries0_38mm
  278. /// Device is an [Apple Watch (1st generation)](https://support.apple.com/kb/SP735)
  279. ///
  280. /// ![Image](https://km.support.apple.com/resources/sites/APPLE/content/live/IMAGES/0/IM784/en_US/apple_watch_sport-240.png)
  281. case appleWatchSeries0_42mm
  282. /// Device is an [Apple Watch Series 1](https://support.apple.com/kb/SP745)
  283. ///
  284. /// ![Image](https://km.support.apple.com/resources/sites/APPLE/content/live/IMAGES/0/IM848/en_US/applewatch-series2-aluminum-temp-240.png)
  285. case appleWatchSeries1_38mm
  286. /// Device is an [Apple Watch Series 1](https://support.apple.com/kb/SP745)
  287. ///
  288. /// ![Image](https://km.support.apple.com/resources/sites/APPLE/content/live/IMAGES/0/IM848/en_US/applewatch-series2-aluminum-temp-240.png)
  289. case appleWatchSeries1_42mm
  290. /// Device is an [Apple Watch Series 2](https://support.apple.com/kb/SP746)
  291. ///
  292. /// ![Image](https://km.support.apple.com/resources/sites/APPLE/content/live/IMAGES/0/IM852/en_US/applewatch-series2-hermes-240.png)
  293. case appleWatchSeries2_38mm
  294. /// Device is an [Apple Watch Series 2](https://support.apple.com/kb/SP746)
  295. ///
  296. /// ![Image](https://km.support.apple.com/resources/sites/APPLE/content/live/IMAGES/0/IM852/en_US/applewatch-series2-hermes-240.png)
  297. case appleWatchSeries2_42mm
  298. /// Device is an [Apple Watch Series 3](https://support.apple.com/kb/SP766)
  299. ///
  300. /// ![Image](https://km.support.apple.com/resources/sites/APPLE/content/live/IMAGES/0/IM893/en_US/apple-watch-s3-nikeplus-240.png)
  301. case appleWatchSeries3_38mm
  302. /// Device is an [Apple Watch Series 3](https://support.apple.com/kb/SP766)
  303. ///
  304. /// ![Image](https://km.support.apple.com/resources/sites/APPLE/content/live/IMAGES/0/IM893/en_US/apple-watch-s3-nikeplus-240.png)
  305. case appleWatchSeries3_42mm
  306. /// Device is an [Apple Watch Series 4](https://support.apple.com/kb/SP778)
  307. ///
  308. /// ![Image](https://km.support.apple.com/resources/sites/APPLE/content/live/IMAGES/0/IM911/en_US/aw-series4-nike-240.png)
  309. case appleWatchSeries4_40mm
  310. /// Device is an [Apple Watch Series 4](https://support.apple.com/kb/SP778)
  311. ///
  312. /// ![Image](https://km.support.apple.com/resources/sites/APPLE/content/live/IMAGES/0/IM911/en_US/aw-series4-nike-240.png)
  313. case appleWatchSeries4_44mm
  314. /// Device is an [Apple Watch Series 5](https://support.apple.com/kb/SP808)
  315. ///
  316. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP808/sp808-apple-watch-series-5_2x.png)
  317. case appleWatchSeries5_40mm
  318. /// Device is an [Apple Watch Series 5](https://support.apple.com/kb/SP808)
  319. ///
  320. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP808/sp808-apple-watch-series-5_2x.png)
  321. case appleWatchSeries5_44mm
  322. /// Device is an [Apple Watch Series 6](https://support.apple.com/kb/SP826)
  323. ///
  324. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP826/sp826-apple-watch-series6-580_2x.png)
  325. case appleWatchSeries6_40mm
  326. /// Device is an [Apple Watch Series 6](https://support.apple.com/kb/SP826)
  327. ///
  328. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP826/sp826-apple-watch-series6-580_2x.png)
  329. case appleWatchSeries6_44mm
  330. /// Device is an [Apple Watch SE](https://support.apple.com/kb/SP827)
  331. ///
  332. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP827/sp827-apple-watch-se-580_2x.png)
  333. case appleWatchSE_40mm
  334. /// Device is an [Apple Watch SE](https://support.apple.com/kb/SP827)
  335. ///
  336. /// ![Image](https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP827/sp827-apple-watch-se-580_2x.png)
  337. case appleWatchSE_44mm
  338. #endif
  339. /// Device is [Simulator](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/iOS_Simulator_Guide/Introduction/Introduction.html)
  340. ///
  341. /// ![Image](https://developer.apple.com/assets/elements/icons/256x256/xcode-6.png)
  342. indirect case simulator(Device)
  343. /// Device is not yet known (implemented)
  344. /// You can still use this enum as before but the description equals the identifier (you can get multiple identifiers for the same product class
  345. /// (e.g. "iPhone6,1" or "iPhone 6,2" do both mean "iPhone 5s"))
  346. case unknown(String)
  347. /// Returns a `Device` representing the current device this software runs on.
  348. public static var current: Device {
  349. return Device.mapToDevice(identifier: Device.identifier)
  350. }
  351. /// Gets the identifier from the system, such as "iPhone7,1".
  352. public static var identifier: String = {
  353. var systemInfo = utsname()
  354. uname(&systemInfo)
  355. let mirror = Mirror(reflecting: systemInfo.machine)
  356. let identifier = mirror.children.reduce("") { identifier, element in
  357. guard let value = element.value as? Int8, value != 0 else { return identifier }
  358. return identifier + String(UnicodeScalar(UInt8(value)))
  359. }
  360. return identifier
  361. }()
  362. /// Maps an identifier to a Device. If the identifier can not be mapped to an existing device, `UnknownDevice(identifier)` is returned.
  363. ///
  364. /// - parameter identifier: The device identifier, e.g. "iPhone7,1". Can be obtained from `Device.identifier`.
  365. ///
  366. /// - returns: An initialized `Device`.
  367. public static func mapToDevice(identifier: String) -> Device { // swiftlint:disable:this cyclomatic_complexity function_body_length
  368. #if os(iOS)
  369. switch identifier {
  370. case "iPod5,1": return iPodTouch5
  371. case "iPod7,1": return iPodTouch6
  372. case "iPod9,1": return iPodTouch7
  373. case "iPhone3,1", "iPhone3,2", "iPhone3,3": return iPhone4
  374. case "iPhone4,1": return iPhone4s
  375. case "iPhone5,1", "iPhone5,2": return iPhone5
  376. case "iPhone5,3", "iPhone5,4": return iPhone5c
  377. case "iPhone6,1", "iPhone6,2": return iPhone5s
  378. case "iPhone7,2": return iPhone6
  379. case "iPhone7,1": return iPhone6Plus
  380. case "iPhone8,1": return iPhone6s
  381. case "iPhone8,2": return iPhone6sPlus
  382. case "iPhone9,1", "iPhone9,3": return iPhone7
  383. case "iPhone9,2", "iPhone9,4": return iPhone7Plus
  384. case "iPhone8,4": return iPhoneSE
  385. case "iPhone10,1", "iPhone10,4": return iPhone8
  386. case "iPhone10,2", "iPhone10,5": return iPhone8Plus
  387. case "iPhone10,3", "iPhone10,6": return iPhoneX
  388. case "iPhone11,2": return iPhoneXS
  389. case "iPhone11,4", "iPhone11,6": return iPhoneXSMax
  390. case "iPhone11,8": return iPhoneXR
  391. case "iPhone12,1": return iPhone11
  392. case "iPhone12,3": return iPhone11Pro
  393. case "iPhone12,5": return iPhone11ProMax
  394. case "iPhone12,8": return iPhoneSE2
  395. case "iPhone13,2": return iPhone12
  396. case "iPhone13,1": return iPhone12Mini
  397. case "iPhone13,3": return iPhone12Pro
  398. case "iPhone13,4": return iPhone12ProMax
  399. case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4": return iPad2
  400. case "iPad3,1", "iPad3,2", "iPad3,3": return iPad3
  401. case "iPad3,4", "iPad3,5", "iPad3,6": return iPad4
  402. case "iPad4,1", "iPad4,2", "iPad4,3": return iPadAir
  403. case "iPad5,3", "iPad5,4": return iPadAir2
  404. case "iPad6,11", "iPad6,12": return iPad5
  405. case "iPad7,5", "iPad7,6": return iPad6
  406. case "iPad11,3", "iPad11,4": return iPadAir3
  407. case "iPad7,11", "iPad7,12": return iPad7
  408. case "iPad11,6", "iPad11,7": return iPad8
  409. case "iPad13,1", "iPad13,2": return iPadAir4
  410. case "iPad2,5", "iPad2,6", "iPad2,7": return iPadMini
  411. case "iPad4,4", "iPad4,5", "iPad4,6": return iPadMini2
  412. case "iPad4,7", "iPad4,8", "iPad4,9": return iPadMini3
  413. case "iPad5,1", "iPad5,2": return iPadMini4
  414. case "iPad11,1", "iPad11,2": return iPadMini5
  415. case "iPad6,3", "iPad6,4": return iPadPro9Inch
  416. case "iPad6,7", "iPad6,8": return iPadPro12Inch
  417. case "iPad7,1", "iPad7,2": return iPadPro12Inch2
  418. case "iPad7,3", "iPad7,4": return iPadPro10Inch
  419. case "iPad8,1", "iPad8,2", "iPad8,3", "iPad8,4": return iPadPro11Inch
  420. case "iPad8,5", "iPad8,6", "iPad8,7", "iPad8,8": return iPadPro12Inch3
  421. case "iPad8,9", "iPad8,10": return iPadPro11Inch2
  422. case "iPad8,11", "iPad8,12": return iPadPro12Inch4
  423. case "AudioAccessory1,1": return homePod
  424. case "i386", "x86_64": return simulator(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "iOS"))
  425. default: return unknown(identifier)
  426. }
  427. #elseif os(tvOS)
  428. switch identifier {
  429. case "AppleTV5,3": return appleTVHD
  430. case "AppleTV6,2": return appleTV4K
  431. case "i386", "x86_64": return simulator(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "tvOS"))
  432. default: return unknown(identifier)
  433. }
  434. #elseif os(watchOS)
  435. switch identifier {
  436. case "Watch1,1": return appleWatchSeries0_38mm
  437. case "Watch1,2": return appleWatchSeries0_42mm
  438. case "Watch2,6": return appleWatchSeries1_38mm
  439. case "Watch2,7": return appleWatchSeries1_42mm
  440. case "Watch2,3": return appleWatchSeries2_38mm
  441. case "Watch2,4": return appleWatchSeries2_42mm
  442. case "Watch3,1", "Watch3,3": return appleWatchSeries3_38mm
  443. case "Watch3,2", "Watch3,4": return appleWatchSeries3_42mm
  444. case "Watch4,1", "Watch4,3": return appleWatchSeries4_40mm
  445. case "Watch4,2", "Watch4,4": return appleWatchSeries4_44mm
  446. case "Watch5,1", "Watch5,3": return appleWatchSeries5_40mm
  447. case "Watch5,2", "Watch5,4": return appleWatchSeries5_44mm
  448. case "Watch6,1", "Watch6,3": return appleWatchSeries6_40mm
  449. case "Watch6,2", "Watch6,4": return appleWatchSeries6_44mm
  450. case "Watch5,9", "Watch5,11": return appleWatchSE_40mm
  451. case "Watch5,10", "Watch5,12": return appleWatchSE_44mm
  452. case "i386", "x86_64": return simulator(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "watchOS"))
  453. default: return unknown(identifier)
  454. }
  455. #endif
  456. }
  457. /// Get the real device from a device.
  458. /// If the device is a an iPhone8Plus simulator this function returns .iPhone8Plus (the real device).
  459. /// If the parameter is a real device, this function returns just that passed parameter.
  460. ///
  461. /// - parameter device: A device.
  462. ///
  463. /// - returns: the underlying device If the `device` is a `simulator`,
  464. /// otherwise return the `device`.
  465. public static func realDevice(from device: Device) -> Device {
  466. if case let .simulator(model) = device {
  467. return model
  468. }
  469. return device
  470. }
  471. #if os(iOS) || os(watchOS)
  472. /// Returns diagonal screen length in inches
  473. public var diagonal: Double {
  474. #if os(iOS)
  475. switch self {
  476. case .iPodTouch5: return 4
  477. case .iPodTouch6: return 4
  478. case .iPodTouch7: return 4
  479. case .iPhone4: return 3.5
  480. case .iPhone4s: return 3.5
  481. case .iPhone5: return 4
  482. case .iPhone5c: return 4
  483. case .iPhone5s: return 4
  484. case .iPhone6: return 4.7
  485. case .iPhone6Plus: return 5.5
  486. case .iPhone6s: return 4.7
  487. case .iPhone6sPlus: return 5.5
  488. case .iPhone7: return 4.7
  489. case .iPhone7Plus: return 5.5
  490. case .iPhoneSE: return 4
  491. case .iPhone8: return 4.7
  492. case .iPhone8Plus: return 5.5
  493. case .iPhoneX: return 5.8
  494. case .iPhoneXS: return 5.8
  495. case .iPhoneXSMax: return 6.5
  496. case .iPhoneXR: return 6.1
  497. case .iPhone11: return 6.1
  498. case .iPhone11Pro: return 5.8
  499. case .iPhone11ProMax: return 6.5
  500. case .iPhoneSE2: return 4.7
  501. case .iPhone12: return 6.1
  502. case .iPhone12Mini: return 5.4
  503. case .iPhone12Pro: return 6.1
  504. case .iPhone12ProMax: return 6.7
  505. case .iPad2: return 9.7
  506. case .iPad3: return 9.7
  507. case .iPad4: return 9.7
  508. case .iPadAir: return 9.7
  509. case .iPadAir2: return 9.7
  510. case .iPad5: return 9.7
  511. case .iPad6: return 9.7
  512. case .iPadAir3: return 10.5
  513. case .iPad7: return 10.2
  514. case .iPad8: return 10.2
  515. case .iPadAir4: return 10.9
  516. case .iPadMini: return 7.9
  517. case .iPadMini2: return 7.9
  518. case .iPadMini3: return 7.9
  519. case .iPadMini4: return 7.9
  520. case .iPadMini5: return 7.9
  521. case .iPadPro9Inch: return 9.7
  522. case .iPadPro12Inch: return 12.9
  523. case .iPadPro12Inch2: return 12.9
  524. case .iPadPro10Inch: return 10.5
  525. case .iPadPro11Inch: return 11.0
  526. case .iPadPro12Inch3: return 12.9
  527. case .iPadPro11Inch2: return 11.0
  528. case .iPadPro12Inch4: return 12.9
  529. case .homePod: return -1
  530. case .simulator(let model): return model.diagonal
  531. case .unknown: return -1
  532. }
  533. #elseif os(watchOS)
  534. switch self {
  535. case .appleWatchSeries0_38mm: return 1.5
  536. case .appleWatchSeries0_42mm: return 1.6
  537. case .appleWatchSeries1_38mm: return 1.5
  538. case .appleWatchSeries1_42mm: return 1.6
  539. case .appleWatchSeries2_38mm: return 1.5
  540. case .appleWatchSeries2_42mm: return 1.6
  541. case .appleWatchSeries3_38mm: return 1.5
  542. case .appleWatchSeries3_42mm: return 1.6
  543. case .appleWatchSeries4_40mm: return 1.8
  544. case .appleWatchSeries4_44mm: return 2.0
  545. case .appleWatchSeries5_40mm: return 1.8
  546. case .appleWatchSeries5_44mm: return 2.0
  547. case .appleWatchSeries6_40mm: return 1.8
  548. case .appleWatchSeries6_44mm: return 2.0
  549. case .appleWatchSE_40mm: return 1.8
  550. case .appleWatchSE_44mm: return 2.0
  551. case .simulator(let model): return model.diagonal
  552. case .unknown: return -1
  553. }
  554. #endif
  555. }
  556. #endif
  557. /// Returns screen ratio as a tuple
  558. public var screenRatio: (width: Double, height: Double) {
  559. #if os(iOS)
  560. switch self {
  561. case .iPodTouch5: return (width: 9, height: 16)
  562. case .iPodTouch6: return (width: 9, height: 16)
  563. case .iPodTouch7: return (width: 9, height: 16)
  564. case .iPhone4: return (width: 2, height: 3)
  565. case .iPhone4s: return (width: 2, height: 3)
  566. case .iPhone5: return (width: 9, height: 16)
  567. case .iPhone5c: return (width: 9, height: 16)
  568. case .iPhone5s: return (width: 9, height: 16)
  569. case .iPhone6: return (width: 9, height: 16)
  570. case .iPhone6Plus: return (width: 9, height: 16)
  571. case .iPhone6s: return (width: 9, height: 16)
  572. case .iPhone6sPlus: return (width: 9, height: 16)
  573. case .iPhone7: return (width: 9, height: 16)
  574. case .iPhone7Plus: return (width: 9, height: 16)
  575. case .iPhoneSE: return (width: 9, height: 16)
  576. case .iPhone8: return (width: 9, height: 16)
  577. case .iPhone8Plus: return (width: 9, height: 16)
  578. case .iPhoneX: return (width: 9, height: 19.5)
  579. case .iPhoneXS: return (width: 9, height: 19.5)
  580. case .iPhoneXSMax: return (width: 9, height: 19.5)
  581. case .iPhoneXR: return (width: 9, height: 19.5)
  582. case .iPhone11: return (width: 9, height: 19.5)
  583. case .iPhone11Pro: return (width: 9, height: 19.5)
  584. case .iPhone11ProMax: return (width: 9, height: 19.5)
  585. case .iPhoneSE2: return (width: 9, height: 16)
  586. case .iPhone12: return (width: 9, height: 19.5)
  587. case .iPhone12Mini: return (width: 9, height: 19.5)
  588. case .iPhone12Pro: return (width: 9, height: 19.5)
  589. case .iPhone12ProMax: return (width: 9, height: 19.5)
  590. case .iPad2: return (width: 3, height: 4)
  591. case .iPad3: return (width: 3, height: 4)
  592. case .iPad4: return (width: 3, height: 4)
  593. case .iPadAir: return (width: 3, height: 4)
  594. case .iPadAir2: return (width: 3, height: 4)
  595. case .iPad5: return (width: 3, height: 4)
  596. case .iPad6: return (width: 3, height: 4)
  597. case .iPadAir3: return (width: 3, height: 4)
  598. case .iPad7: return (width: 3, height: 4)
  599. case .iPad8: return (width: 3, height: 4)
  600. case .iPadAir4: return (width: 41, height: 59)
  601. case .iPadMini: return (width: 3, height: 4)
  602. case .iPadMini2: return (width: 3, height: 4)
  603. case .iPadMini3: return (width: 3, height: 4)
  604. case .iPadMini4: return (width: 3, height: 4)
  605. case .iPadMini5: return (width: 3, height: 4)
  606. case .iPadPro9Inch: return (width: 3, height: 4)
  607. case .iPadPro12Inch: return (width: 3, height: 4)
  608. case .iPadPro12Inch2: return (width: 3, height: 4)
  609. case .iPadPro10Inch: return (width: 3, height: 4)
  610. case .iPadPro11Inch: return (width: 139, height: 199)
  611. case .iPadPro12Inch3: return (width: 512, height: 683)
  612. case .iPadPro11Inch2: return (width: 139, height: 199)
  613. case .iPadPro12Inch4: return (width: 512, height: 683)
  614. case .homePod: return (width: 4, height: 5)
  615. case .simulator(let model): return model.screenRatio
  616. case .unknown: return (width: -1, height: -1)
  617. }
  618. #elseif os(watchOS)
  619. switch self {
  620. case .appleWatchSeries0_38mm: return (width: 4, height: 5)
  621. case .appleWatchSeries0_42mm: return (width: 4, height: 5)
  622. case .appleWatchSeries1_38mm: return (width: 4, height: 5)
  623. case .appleWatchSeries1_42mm: return (width: 4, height: 5)
  624. case .appleWatchSeries2_38mm: return (width: 4, height: 5)
  625. case .appleWatchSeries2_42mm: return (width: 4, height: 5)
  626. case .appleWatchSeries3_38mm: return (width: 4, height: 5)
  627. case .appleWatchSeries3_42mm: return (width: 4, height: 5)
  628. case .appleWatchSeries4_40mm: return (width: 4, height: 5)
  629. case .appleWatchSeries4_44mm: return (width: 4, height: 5)
  630. case .appleWatchSeries5_40mm: return (width: 4, height: 5)
  631. case .appleWatchSeries5_44mm: return (width: 4, height: 5)
  632. case .appleWatchSeries6_40mm: return (width: 4, height: 5)
  633. case .appleWatchSeries6_44mm: return (width: 4, height: 5)
  634. case .appleWatchSE_40mm: return (width: 4, height: 5)
  635. case .appleWatchSE_44mm: return (width: 4, height: 5)
  636. case .simulator(let model): return model.screenRatio
  637. case .unknown: return (width: -1, height: -1)
  638. }
  639. #elseif os(tvOS)
  640. return (width: -1, height: -1)
  641. #endif
  642. }
  643. #if os(iOS)
  644. /// All iPods
  645. public static var allPods: [Device] {
  646. return [.iPodTouch5, .iPodTouch6, .iPodTouch7]
  647. }
  648. /// All iPhones
  649. public static var allPhones: [Device] {
  650. return [.iPhone4, .iPhone4s, .iPhone5, .iPhone5c, .iPhone5s, .iPhone6, .iPhone6Plus, .iPhone6s, .iPhone6sPlus, .iPhone7, .iPhone7Plus, .iPhoneSE, .iPhone8, .iPhone8Plus, .iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPhoneSE2, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax]
  651. }
  652. /// All iPads
  653. public static var allPads: [Device] {
  654. return [.iPad2, .iPad3, .iPad4, .iPadAir, .iPadAir2, .iPad5, .iPad6, .iPadAir3, .iPad7, .iPad8, .iPadAir4, .iPadMini, .iPadMini2, .iPadMini3, .iPadMini4, .iPadMini5, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4]
  655. }
  656. /// All X-Series Devices
  657. @available(*, deprecated, renamed: "allDevicesWithSensorHousing")
  658. public static var allXSeriesDevices: [Device] {
  659. return [.iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax]
  660. }
  661. /// All Plus and Max-Sized Devices
  662. public static var allPlusSizedDevices: [Device] {
  663. return [.iPhone6Plus, .iPhone6sPlus, .iPhone7Plus, .iPhone8Plus, .iPhoneXSMax, .iPhone11ProMax, .iPhone12ProMax]
  664. }
  665. /// All Pro Devices
  666. public static var allProDevices: [Device] {
  667. return [.iPhone11Pro, .iPhone11ProMax, .iPhone12Pro, .iPhone12ProMax, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4]
  668. }
  669. /// All mini Devices
  670. public static var allMiniDevices: [Device] {
  671. return [.iPadMini, .iPadMini2, .iPadMini3, .iPadMini4, .iPadMini5]
  672. }
  673. /// All simulator iPods
  674. public static var allSimulatorPods: [Device] {
  675. return allPods.map(Device.simulator)
  676. }
  677. /// All simulator iPhones
  678. public static var allSimulatorPhones: [Device] {
  679. return allPhones.map(Device.simulator)
  680. }
  681. /// All simulator iPads
  682. public static var allSimulatorPads: [Device] {
  683. return allPads.map(Device.simulator)
  684. }
  685. /// All simulator iPad mini
  686. public static var allSimulatorMiniDevices: [Device] {
  687. return allMiniDevices.map(Device.simulator)
  688. }
  689. /// All simulator X series Devices
  690. @available(*, deprecated, renamed: "allSimulatorDevicesWithSensorHousing")
  691. public static var allSimulatorXSeriesDevices: [Device] {
  692. return allDevicesWithSensorHousing.map(Device.simulator)
  693. }
  694. /// All simulator Plus and Max-Sized Devices
  695. public static var allSimulatorPlusSizedDevices: [Device] {
  696. return allPlusSizedDevices.map(Device.simulator)
  697. }
  698. /// All simulator Pro Devices
  699. public static var allSimulatorProDevices: [Device] {
  700. return allProDevices.map(Device.simulator)
  701. }
  702. /// Returns whether the device is an iPod (real or simulator)
  703. public var isPod: Bool {
  704. return isOneOf(Device.allPods) || isOneOf(Device.allSimulatorPods)
  705. }
  706. /// Returns whether the device is an iPhone (real or simulator)
  707. public var isPhone: Bool {
  708. return (isOneOf(Device.allPhones)
  709. || isOneOf(Device.allSimulatorPhones)
  710. || (UIDevice.current.userInterfaceIdiom == .phone && isCurrent)) && !isPod
  711. }
  712. /// Returns whether the device is an iPad (real or simulator)
  713. public var isPad: Bool {
  714. return isOneOf(Device.allPads)
  715. || isOneOf(Device.allSimulatorPads)
  716. || (UIDevice.current.userInterfaceIdiom == .pad && isCurrent)
  717. }
  718. /// Returns whether the device is any of the simulator
  719. /// Useful when there is a need to check and skip running a portion of code (location request or others)
  720. public var isSimulator: Bool {
  721. return isOneOf(Device.allSimulators)
  722. }
  723. /// If this device is a simulator return the underlying device,
  724. /// otherwise return `self`.
  725. public var realDevice: Device {
  726. return Device.realDevice(from: self)
  727. }
  728. public var isZoomed: Bool? {
  729. guard isCurrent else { return nil }
  730. if Int(UIScreen.main.scale.rounded()) == 3 {
  731. // Plus-sized
  732. return UIScreen.main.nativeScale > 2.7 && UIScreen.main.nativeScale < 3
  733. } else {
  734. return UIScreen.main.nativeScale > UIScreen.main.scale
  735. }
  736. }
  737. /// All Touch ID Capable Devices
  738. public static var allTouchIDCapableDevices: [Device] {
  739. return [.iPhone5s, .iPhone6, .iPhone6Plus, .iPhone6s, .iPhone6sPlus, .iPhone7, .iPhone7Plus, .iPhoneSE, .iPhone8, .iPhone8Plus, .iPhoneSE2, .iPadAir2, .iPad5, .iPad6, .iPadAir3, .iPad7, .iPad8, .iPadAir4, .iPadMini3, .iPadMini4, .iPadMini5, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch]
  740. }
  741. /// All Face ID Capable Devices
  742. public static var allFaceIDCapableDevices: [Device] {
  743. return [.iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4]
  744. }
  745. /// All Devices with Touch ID or Face ID
  746. public static var allBiometricAuthenticationCapableDevices: [Device] {
  747. return [.iPhone5s, .iPhone6, .iPhone6Plus, .iPhone6s, .iPhone6sPlus, .iPhone7, .iPhone7Plus, .iPhoneSE, .iPhone8, .iPhone8Plus, .iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPhoneSE2, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax, .iPadAir2, .iPad5, .iPad6, .iPadAir3, .iPad7, .iPad8, .iPadAir4, .iPadMini3, .iPadMini4, .iPadMini5, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4]
  748. }
  749. /// Returns whether or not the device has Touch ID
  750. public var isTouchIDCapable: Bool {
  751. return isOneOf(Device.allTouchIDCapableDevices) || isOneOf(Device.allTouchIDCapableDevices.map(Device.simulator))
  752. }
  753. /// Returns whether or not the device has Face ID
  754. public var isFaceIDCapable: Bool {
  755. return isOneOf(Device.allFaceIDCapableDevices) || isOneOf(Device.allFaceIDCapableDevices.map(Device.simulator))
  756. }
  757. /// Returns whether or not the device has any biometric sensor (i.e. Touch ID or Face ID)
  758. public var hasBiometricSensor: Bool {
  759. return isTouchIDCapable || isFaceIDCapable
  760. }
  761. /// All devices that feature a sensor housing in the screen
  762. public static var allDevicesWithSensorHousing: [Device] {
  763. return [.iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax]
  764. }
  765. /// All simulator devices that feature a sensor housing in the screen
  766. public static var allSimulatorDevicesWithSensorHousing: [Device] {
  767. return allDevicesWithSensorHousing.map(Device.simulator)
  768. }
  769. /// Returns whether or not the device has a sensor housing
  770. public var hasSensorHousing: Bool {
  771. return isOneOf(Device.allDevicesWithSensorHousing) || isOneOf(Device.allDevicesWithSensorHousing.map(Device.simulator))
  772. }
  773. /// All devices that feature a screen with rounded corners.
  774. public static var allDevicesWithRoundedDisplayCorners: [Device] {
  775. return [.iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax, .iPadAir4, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4]
  776. }
  777. /// Returns whether or not the device has a screen with rounded corners.
  778. public var hasRoundedDisplayCorners: Bool {
  779. return isOneOf(Device.allDevicesWithRoundedDisplayCorners) || isOneOf(Device.allDevicesWithRoundedDisplayCorners.map(Device.simulator))
  780. }
  781. /// All devices that have 3D Touch support.
  782. public static var allDevicesWith3dTouchSupport: [Device] {
  783. return [.iPhone6s, .iPhone6sPlus, .iPhone7, .iPhone7Plus, .iPhone8, .iPhone8Plus, .iPhoneX, .iPhoneXS, .iPhoneXSMax]
  784. }
  785. /// Returns whether or not the device has 3D Touch support.
  786. public var has3dTouchSupport: Bool {
  787. return isOneOf(Device.allDevicesWith3dTouchSupport) || isOneOf(Device.allDevicesWith3dTouchSupport.map(Device.simulator))
  788. }
  789. /// All devices that support wireless charging.
  790. public static var allDevicesWithWirelessChargingSupport: [Device] {
  791. return [.iPhone8, .iPhone8Plus, .iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhoneXR, .iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPhoneSE2, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax]
  792. }
  793. /// Returns whether or not the device supports wireless charging.
  794. public var supportsWirelessCharging: Bool {
  795. return isOneOf(Device.allDevicesWithWirelessChargingSupport) || isOneOf(Device.allDevicesWithWirelessChargingSupport.map(Device.simulator))
  796. }
  797. /// All devices that have a LiDAR sensor.
  798. public static var allDevicesWithALidarSensor: [Device] {
  799. return [.iPhone12Pro, .iPhone12ProMax, .iPadPro11Inch2, .iPadPro12Inch4]
  800. }
  801. /// Returns whether or not the device has a LiDAR sensor.
  802. public var hasLidarSensor: Bool {
  803. return isOneOf(Device.allDevicesWithALidarSensor) || isOneOf(Device.allDevicesWithALidarSensor.map(Device.simulator))
  804. }
  805. #elseif os(tvOS)
  806. /// All TVs
  807. public static var allTVs: [Device] {
  808. return [.appleTVHD, .appleTV4K]
  809. }
  810. /// All simulator TVs
  811. public static var allSimulatorTVs: [Device] {
  812. return allTVs.map(Device.simulator)
  813. }
  814. #elseif os(watchOS)
  815. /// All Watches
  816. public static var allWatches: [Device] {
  817. 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, .appleWatchSeries6_40mm, .appleWatchSeries6_44mm, .appleWatchSE_40mm, .appleWatchSE_44mm]
  818. }
  819. /// All simulator Watches
  820. public static var allSimulatorWatches: [Device] {
  821. return allWatches.map(Device.simulator)
  822. }
  823. /// All watches that have Force Touch support.
  824. public static var allWatchesWithForceTouchSupport: [Device] {
  825. 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]
  826. }
  827. /// Returns whether or not the device has Force Touch support.
  828. public var hasForceTouchSupport: Bool {
  829. return isOneOf(Device.allWatchesWithForceTouchSupport) || isOneOf(Device.allWatchesWithForceTouchSupport.map(Device.simulator))
  830. }
  831. #endif
  832. /// All real devices (i.e. all devices except for all simulators)
  833. public static var allRealDevices: [Device] {
  834. #if os(iOS)
  835. return allPods + allPhones + allPads
  836. #elseif os(tvOS)
  837. return allTVs
  838. #elseif os(watchOS)
  839. return allWatches
  840. #endif
  841. }
  842. /// All simulators
  843. public static var allSimulators: [Device] {
  844. return allRealDevices.map(Device.simulator)
  845. }
  846. /**
  847. This method saves you in many cases from the need of updating your code with every new device.
  848. Most uses for an enum like this are the following:
  849. ```
  850. switch Device.current {
  851. case .iPodTouch5, .iPodTouch6: callMethodOnIPods()
  852. case .iPhone4, iPhone4s, .iPhone5, .iPhone5s, .iPhone6, .iPhone6Plus, .iPhone6s, .iPhone6sPlus, .iPhone7, .iPhone7Plus, .iPhoneSE, .iPhone8, .iPhone8Plus, .iPhoneX: callMethodOnIPhones()
  853. case .iPad2, .iPad3, .iPad4, .iPadAir, .iPadAir2, .iPadMini, .iPadMini2, .iPadMini3, .iPadMini4, .iPadPro: callMethodOnIPads()
  854. default: break
  855. }
  856. ```
  857. This code can now be replaced with
  858. ```
  859. let device = Device.current
  860. if device.isOneOf(Device.allPods) {
  861. callMethodOnIPods()
  862. } else if device.isOneOf(Device.allPhones) {
  863. callMethodOnIPhones()
  864. } else if device.isOneOf(Device.allPads) {
  865. callMethodOnIPads()
  866. }
  867. ```
  868. - parameter devices: An array of devices.
  869. - returns: Returns whether the current device is one of the passed in ones.
  870. */
  871. public func isOneOf(_ devices: [Device]) -> Bool {
  872. return devices.contains(self)
  873. }
  874. // MARK: Current Device
  875. /// Whether or not the current device is the current device.
  876. private var isCurrent: Bool {
  877. return self == Device.current
  878. }
  879. /// The name identifying the device (e.g. "Dennis' iPhone").
  880. public var name: String? {
  881. guard isCurrent else { return nil }
  882. #if os(watchOS)
  883. return WKInterfaceDevice.current().name
  884. #else
  885. return UIDevice.current.name
  886. #endif
  887. }
  888. /// The name of the operating system running on the device represented by the receiver (e.g. "iOS" or "tvOS").
  889. public var systemName: String? {
  890. guard isCurrent else { return nil }
  891. #if os(watchOS)
  892. return WKInterfaceDevice.current().systemName
  893. #else
  894. return UIDevice.current.systemName
  895. #endif
  896. }
  897. /// The current version of the operating system (e.g. 8.4 or 9.2).
  898. public var systemVersion: String? {
  899. guard isCurrent else { return nil }
  900. #if os(watchOS)
  901. return WKInterfaceDevice.current().systemVersion
  902. #else
  903. return UIDevice.current.systemVersion
  904. #endif
  905. }
  906. /// The model of the device (e.g. "iPhone" or "iPod Touch").
  907. public var model: String? {
  908. guard isCurrent else { return nil }
  909. #if os(watchOS)
  910. return WKInterfaceDevice.current().model
  911. #else
  912. return UIDevice.current.model
  913. #endif
  914. }
  915. /// The model of the device as a localized string.
  916. public var localizedModel: String? {
  917. guard isCurrent else { return nil }
  918. #if os(watchOS)
  919. return WKInterfaceDevice.current().localizedModel
  920. #else
  921. return UIDevice.current.localizedModel
  922. #endif
  923. }
  924. /// PPI (Pixels per Inch) on the current device's screen (if applicable). When the device is not applicable this property returns nil.
  925. public var ppi: Int? {
  926. #if os(iOS)
  927. switch self {
  928. case .iPodTouch5: return 326
  929. case .iPodTouch6: return 326
  930. case .iPodTouch7: return 326
  931. case .iPhone4: return 326
  932. case .iPhone4s: return 326
  933. case .iPhone5: return 326
  934. case .iPhone5c: return 326
  935. case .iPhone5s: return 326
  936. case .iPhone6: return 326
  937. case .iPhone6Plus: return 401
  938. case .iPhone6s: return 326
  939. case .iPhone6sPlus: return 401
  940. case .iPhone7: return 326
  941. case .iPhone7Plus: return 401
  942. case .iPhoneSE: return 326
  943. case .iPhone8: return 326
  944. case .iPhone8Plus: return 401
  945. case .iPhoneX: return 458
  946. case .iPhoneXS: return 458
  947. case .iPhoneXSMax: return 458
  948. case .iPhoneXR: return 326
  949. case .iPhone11: return 326
  950. case .iPhone11Pro: return 458
  951. case .iPhone11ProMax: return 458
  952. case .iPhoneSE2: return 326
  953. case .iPhone12: return 460
  954. case .iPhone12Mini: return 476
  955. case .iPhone12Pro: return 460
  956. case .iPhone12ProMax: return 458
  957. case .iPad2: return 132
  958. case .iPad3: return 264
  959. case .iPad4: return 264
  960. case .iPadAir: return 264
  961. case .iPadAir2: return 264
  962. case .iPad5: return 264
  963. case .iPad6: return 264
  964. case .iPadAir3: return 264
  965. case .iPad7: return 264
  966. case .iPad8: return 264
  967. case .iPadAir4: return 264
  968. case .iPadMini: return 163
  969. case .iPadMini2: return 326
  970. case .iPadMini3: return 326
  971. case .iPadMini4: return 326
  972. case .iPadMini5: return 326
  973. case .iPadPro9Inch: return 264
  974. case .iPadPro12Inch: return 264
  975. case .iPadPro12Inch2: return 264
  976. case .iPadPro10Inch: return 264
  977. case .iPadPro11Inch: return 264
  978. case .iPadPro12Inch3: return 264
  979. case .iPadPro11Inch2: return 264
  980. case .iPadPro12Inch4: return 264
  981. case .homePod: return -1
  982. case .simulator(let model): return model.ppi
  983. case .unknown: return nil
  984. }
  985. #elseif os(watchOS)
  986. switch self {
  987. case .appleWatchSeries0_38mm: return 290
  988. case .appleWatchSeries0_42mm: return 303
  989. case .appleWatchSeries1_38mm: return 290
  990. case .appleWatchSeries1_42mm: return 303
  991. case .appleWatchSeries2_38mm: return 290
  992. case .appleWatchSeries2_42mm: return 303
  993. case .appleWatchSeries3_38mm: return 290
  994. case .appleWatchSeries3_42mm: return 303
  995. case .appleWatchSeries4_40mm: return 326
  996. case .appleWatchSeries4_44mm: return 326
  997. case .appleWatchSeries5_40mm: return 326
  998. case .appleWatchSeries5_44mm: return 326
  999. case .appleWatchSeries6_40mm: return 326
  1000. case .appleWatchSeries6_44mm: return 326
  1001. case .appleWatchSE_40mm: return 326
  1002. case .appleWatchSE_44mm: return 326
  1003. case .simulator(let model): return model.ppi
  1004. case .unknown: return nil
  1005. }
  1006. #elseif os(tvOS)
  1007. return nil
  1008. #endif
  1009. }
  1010. /// True when a Guided Access session is currently active; otherwise, false.
  1011. public var isGuidedAccessSessionActive: Bool {
  1012. #if os(iOS)
  1013. #if swift(>=4.2)
  1014. return UIAccessibility.isGuidedAccessEnabled
  1015. #else
  1016. return UIAccessibilityIsGuidedAccessEnabled()
  1017. #endif
  1018. #else
  1019. return false
  1020. #endif
  1021. }
  1022. /// The brightness level of the screen.
  1023. public var screenBrightness: Int {
  1024. #if os(iOS)
  1025. return Int(UIScreen.main.brightness * 100)
  1026. #else
  1027. return 100
  1028. #endif
  1029. }
  1030. }
  1031. // MARK: CustomStringConvertible
  1032. extension Device: CustomStringConvertible {
  1033. /// A textual representation of the device.
  1034. public var description: String {
  1035. #if os(iOS)
  1036. switch self {
  1037. case .iPodTouch5: return "iPod touch (5th generation)"
  1038. case .iPodTouch6: return "iPod touch (6th generation)"
  1039. case .iPodTouch7: return "iPod touch (7th generation)"
  1040. case .iPhone4: return "iPhone 4"
  1041. case .iPhone4s: return "iPhone 4s"
  1042. case .iPhone5: return "iPhone 5"
  1043. case .iPhone5c: return "iPhone 5c"
  1044. case .iPhone5s: return "iPhone 5s"
  1045. case .iPhone6: return "iPhone 6"
  1046. case .iPhone6Plus: return "iPhone 6 Plus"
  1047. case .iPhone6s: return "iPhone 6s"
  1048. case .iPhone6sPlus: return "iPhone 6s Plus"
  1049. case .iPhone7: return "iPhone 7"
  1050. case .iPhone7Plus: return "iPhone 7 Plus"
  1051. case .iPhoneSE: return "iPhone SE"
  1052. case .iPhone8: return "iPhone 8"
  1053. case .iPhone8Plus: return "iPhone 8 Plus"
  1054. case .iPhoneX: return "iPhone X"
  1055. case .iPhoneXS: return "iPhone Xs"
  1056. case .iPhoneXSMax: return "iPhone Xs Max"
  1057. case .iPhoneXR: return "iPhone Xʀ"
  1058. case .iPhone11: return "iPhone 11"
  1059. case .iPhone11Pro: return "iPhone 11 Pro"
  1060. case .iPhone11ProMax: return "iPhone 11 Pro Max"
  1061. case .iPhoneSE2: return "iPhone SE (2nd generation)"
  1062. case .iPhone12: return "iPhone 12"
  1063. case .iPhone12Mini: return "iPhone 12 mini"
  1064. case .iPhone12Pro: return "iPhone 12 Pro"
  1065. case .iPhone12ProMax: return "iPhone 12 Pro Max"
  1066. case .iPad2: return "iPad 2"
  1067. case .iPad3: return "iPad (3rd generation)"
  1068. case .iPad4: return "iPad (4th generation)"
  1069. case .iPadAir: return "iPad Air"
  1070. case .iPadAir2: return "iPad Air 2"
  1071. case .iPad5: return "iPad (5th generation)"
  1072. case .iPad6: return "iPad (6th generation)"
  1073. case .iPadAir3: return "iPad Air (3rd generation)"
  1074. case .iPad7: return "iPad (7th generation)"
  1075. case .iPad8: return "iPad (8th generation)"
  1076. case .iPadAir4: return "iPad Air (4th generation)"
  1077. case .iPadMini: return "iPad Mini"
  1078. case .iPadMini2: return "iPad Mini 2"
  1079. case .iPadMini3: return "iPad Mini 3"
  1080. case .iPadMini4: return "iPad Mini 4"
  1081. case .iPadMini5: return "iPad Mini (5th generation)"
  1082. case .iPadPro9Inch: return "iPad Pro (9.7-inch)"
  1083. case .iPadPro12Inch: return "iPad Pro (12.9-inch)"
  1084. case .iPadPro12Inch2: return "iPad Pro (12.9-inch) (2nd generation)"
  1085. case .iPadPro10Inch: return "iPad Pro (10.5-inch)"
  1086. case .iPadPro11Inch: return "iPad Pro (11-inch)"
  1087. case .iPadPro12Inch3: return "iPad Pro (12.9-inch) (3rd generation)"
  1088. case .iPadPro11Inch2: return "iPad Pro (11-inch) (2nd generation)"
  1089. case .iPadPro12Inch4: return "iPad Pro (12.9-inch) (4th generation)"
  1090. case .homePod: return "HomePod"
  1091. case .simulator(let model): return "Simulator (\(model.description))"
  1092. case .unknown(let identifier): return identifier
  1093. }
  1094. #elseif os(watchOS)
  1095. switch self {
  1096. case .appleWatchSeries0_38mm: return "Apple Watch (1st generation) 38mm"
  1097. case .appleWatchSeries0_42mm: return "Apple Watch (1st generation) 42mm"
  1098. case .appleWatchSeries1_38mm: return "Apple Watch Series 1 38mm"
  1099. case .appleWatchSeries1_42mm: return "Apple Watch Series 1 42mm"
  1100. case .appleWatchSeries2_38mm: return "Apple Watch Series 2 38mm"
  1101. case .appleWatchSeries2_42mm: return "Apple Watch Series 2 42mm"
  1102. case .appleWatchSeries3_38mm: return "Apple Watch Series 3 38mm"
  1103. case .appleWatchSeries3_42mm: return "Apple Watch Series 3 42mm"
  1104. case .appleWatchSeries4_40mm: return "Apple Watch Series 4 40mm"
  1105. case .appleWatchSeries4_44mm: return "Apple Watch Series 4 44mm"
  1106. case .appleWatchSeries5_40mm: return "Apple Watch Series 5 40mm"
  1107. case .appleWatchSeries5_44mm: return "Apple Watch Series 5 44mm"
  1108. case .appleWatchSeries6_40mm: return "Apple Watch Series 6 40mm"
  1109. case .appleWatchSeries6_44mm: return "Apple Watch Series 6 44mm"
  1110. case .appleWatchSE_40mm: return "Apple Watch SE 40mm"
  1111. case .appleWatchSE_44mm: return "Apple Watch SE 44mm"
  1112. case .simulator(let model): return "Simulator (\(model.description))"
  1113. case .unknown(let identifier): return identifier
  1114. }
  1115. #elseif os(tvOS)
  1116. switch self {
  1117. case .appleTVHD: return "Apple TV HD"
  1118. case .appleTV4K: return "Apple TV 4K"
  1119. case .simulator(let model): return "Simulator (\(model.description))"
  1120. case .unknown(let identifier): return identifier
  1121. }
  1122. #endif
  1123. }
  1124. /// A safe version of `description`.
  1125. /// Example:
  1126. /// Device.iPhoneXR.description: iPhone Xʀ
  1127. /// Device.iPhoneXR.safeDescription: iPhone XR
  1128. public var safeDescription: String {
  1129. #if os(iOS)
  1130. switch self {
  1131. case .iPodTouch5: return "iPod touch (5th generation)"
  1132. case .iPodTouch6: return "iPod touch (6th generation)"
  1133. case .iPodTouch7: return "iPod touch (7th generation)"
  1134. case .iPhone4: return "iPhone 4"
  1135. case .iPhone4s: return "iPhone 4s"
  1136. case .iPhone5: return "iPhone 5"
  1137. case .iPhone5c: return "iPhone 5c"
  1138. case .iPhone5s: return "iPhone 5s"
  1139. case .iPhone6: return "iPhone 6"
  1140. case .iPhone6Plus: return "iPhone 6 Plus"
  1141. case .iPhone6s: return "iPhone 6s"
  1142. case .iPhone6sPlus: return "iPhone 6s Plus"
  1143. case .iPhone7: return "iPhone 7"
  1144. case .iPhone7Plus: return "iPhone 7 Plus"
  1145. case .iPhoneSE: return "iPhone SE"
  1146. case .iPhone8: return "iPhone 8"
  1147. case .iPhone8Plus: return "iPhone 8 Plus"
  1148. case .iPhoneX: return "iPhone X"
  1149. case .iPhoneXS: return "iPhone XS"
  1150. case .iPhoneXSMax: return "iPhone XS Max"
  1151. case .iPhoneXR: return "iPhone XR"
  1152. case .iPhone11: return "iPhone 11"
  1153. case .iPhone11Pro: return "iPhone 11 Pro"
  1154. case .iPhone11ProMax: return "iPhone 11 Pro Max"
  1155. case .iPhoneSE2: return "iPhone SE (2nd generation)"
  1156. case .iPhone12: return "iPhone 12"
  1157. case .iPhone12Mini: return "iPhone 12 mini"
  1158. case .iPhone12Pro: return "iPhone 12 Pro"
  1159. case .iPhone12ProMax: return "iPhone 12 Pro Max"
  1160. case .iPad2: return "iPad 2"
  1161. case .iPad3: return "iPad (3rd generation)"
  1162. case .iPad4: return "iPad (4th generation)"
  1163. case .iPadAir: return "iPad Air"
  1164. case .iPadAir2: return "iPad Air 2"
  1165. case .iPad5: return "iPad (5th generation)"
  1166. case .iPad6: return "iPad (6th generation)"
  1167. case .iPadAir3: return "iPad Air (3rd generation)"
  1168. case .iPad7: return "iPad (7th generation)"
  1169. case .iPad8: return "iPad (8th generation)"
  1170. case .iPadAir4: return "iPad Air (4th generation)"
  1171. case .iPadMini: return "iPad Mini"
  1172. case .iPadMini2: return "iPad Mini 2"
  1173. case .iPadMini3: return "iPad Mini 3"
  1174. case .iPadMini4: return "iPad Mini 4"
  1175. case .iPadMini5: return "iPad Mini (5th generation)"
  1176. case .iPadPro9Inch: return "iPad Pro (9.7-inch)"
  1177. case .iPadPro12Inch: return "iPad Pro (12.9-inch)"
  1178. case .iPadPro12Inch2: return "iPad Pro (12.9-inch) (2nd generation)"
  1179. case .iPadPro10Inch: return "iPad Pro (10.5-inch)"
  1180. case .iPadPro11Inch: return "iPad Pro (11-inch)"
  1181. case .iPadPro12Inch3: return "iPad Pro (12.9-inch) (3rd generation)"
  1182. case .iPadPro11Inch2: return "iPad Pro (11-inch) (2nd generation)"
  1183. case .iPadPro12Inch4: return "iPad Pro (12.9-inch) (4th generation)"
  1184. case .homePod: return "HomePod"
  1185. case .simulator(let model): return "Simulator (\(model.safeDescription))"
  1186. case .unknown(let identifier): return identifier
  1187. }
  1188. #elseif os(watchOS)
  1189. switch self {
  1190. case .appleWatchSeries0_38mm: return "Apple Watch (1st generation) 38mm"
  1191. case .appleWatchSeries0_42mm: return "Apple Watch (1st generation) 42mm"
  1192. case .appleWatchSeries1_38mm: return "Apple Watch Series 1 38mm"
  1193. case .appleWatchSeries1_42mm: return "Apple Watch Series 1 42mm"
  1194. case .appleWatchSeries2_38mm: return "Apple Watch Series 2 38mm"
  1195. case .appleWatchSeries2_42mm: return "Apple Watch Series 2 42mm"
  1196. case .appleWatchSeries3_38mm: return "Apple Watch Series 3 38mm"
  1197. case .appleWatchSeries3_42mm: return "Apple Watch Series 3 42mm"
  1198. case .appleWatchSeries4_40mm: return "Apple Watch Series 4 40mm"
  1199. case .appleWatchSeries4_44mm: return "Apple Watch Series 4 44mm"
  1200. case .appleWatchSeries5_40mm: return "Apple Watch Series 5 40mm"
  1201. case .appleWatchSeries5_44mm: return "Apple Watch Series 5 44mm"
  1202. case .appleWatchSeries6_40mm: return "Apple Watch Series 6 40mm"
  1203. case .appleWatchSeries6_44mm: return "Apple Watch Series 6 44mm"
  1204. case .appleWatchSE_40mm: return "Apple Watch SE 40mm"
  1205. case .appleWatchSE_44mm: return "Apple Watch SE 44mm"
  1206. case .simulator(let model): return "Simulator (\(model.safeDescription))"
  1207. case .unknown(let identifier): return identifier
  1208. }
  1209. #elseif os(tvOS)
  1210. switch self {
  1211. case .appleTVHD: return "Apple TV HD"
  1212. case .appleTV4K: return "Apple TV 4K"
  1213. case .simulator(let model): return "Simulator (\(model.safeDescription))"
  1214. case .unknown(let identifier): return identifier
  1215. }
  1216. #endif
  1217. }
  1218. }
  1219. // MARK: Equatable
  1220. extension Device: Equatable {
  1221. /// Compares two devices
  1222. ///
  1223. /// - parameter lhs: A device.
  1224. /// - parameter rhs: Another device.
  1225. ///
  1226. /// - returns: `true` iff the underlying identifier is the same.
  1227. public static func == (lhs: Device, rhs: Device) -> Bool {
  1228. return lhs.description == rhs.description
  1229. }
  1230. }
  1231. // MARK: Battery
  1232. #if os(iOS) || os(watchOS)
  1233. @available(iOS 8.0, watchOS 4.0, *)
  1234. extension Device {
  1235. /**
  1236. This enum describes the state of the battery.
  1237. - Full: The device is plugged into power and the battery is 100% charged or the device is the iOS Simulator.
  1238. - Charging: The device is plugged into power and the battery is less than 100% charged.
  1239. - Unplugged: The device is not plugged into power; the battery is discharging.
  1240. */
  1241. public enum BatteryState: CustomStringConvertible, Equatable {
  1242. /// The device is plugged into power and the battery is 100% charged or the device is the iOS Simulator.
  1243. case full
  1244. /// The device is plugged into power and the battery is less than 100% charged.
  1245. /// The associated value is in percent (0-100).
  1246. case charging(Int)
  1247. /// The device is not plugged into power; the battery is discharging.
  1248. /// The associated value is in percent (0-100).
  1249. case unplugged(Int)
  1250. #if os(iOS)
  1251. fileprivate init() {
  1252. let wasBatteryMonitoringEnabled = UIDevice.current.isBatteryMonitoringEnabled
  1253. UIDevice.current.isBatteryMonitoringEnabled = true
  1254. 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
  1255. // but maybe that changes in the future.
  1256. switch UIDevice.current.batteryState {
  1257. case .charging: self = .charging(batteryLevel)
  1258. case .full: self = .full
  1259. case .unplugged: self = .unplugged(batteryLevel)
  1260. case .unknown: self = .full // Should never happen since `batteryMonitoring` is enabled.
  1261. @unknown default:
  1262. self = .full // To cover any future additions for which DeviceKit might not have updated yet.
  1263. }
  1264. UIDevice.current.isBatteryMonitoringEnabled = wasBatteryMonitoringEnabled
  1265. }
  1266. #elseif os(watchOS)
  1267. fileprivate init() {
  1268. let wasBatteryMonitoringEnabled = WKInterfaceDevice.current().isBatteryMonitoringEnabled
  1269. WKInterfaceDevice.current().isBatteryMonitoringEnabled = true
  1270. 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
  1271. // but maybe that changes in the future.
  1272. switch WKInterfaceDevice.current().batteryState {
  1273. case .charging: self = .charging(batteryLevel)
  1274. case .full: self = .full
  1275. case .unplugged: self = .unplugged(batteryLevel)
  1276. case .unknown: self = .full // Should never happen since `batteryMonitoring` is enabled.
  1277. @unknown default:
  1278. self = .full // To cover any future additions for which DeviceKit might not have updated yet.
  1279. }
  1280. WKInterfaceDevice.current().isBatteryMonitoringEnabled = wasBatteryMonitoringEnabled
  1281. }
  1282. #endif
  1283. /// The user enabled Low Power mode
  1284. public var lowPowerMode: Bool {
  1285. return ProcessInfo.processInfo.isLowPowerModeEnabled
  1286. }
  1287. /// Provides a textual representation of the battery state.
  1288. /// Examples:
  1289. /// ```
  1290. /// Battery level: 90%, device is plugged in.
  1291. /// Battery level: 100 % (Full), device is plugged in.
  1292. /// Battery level: \(batteryLevel)%, device is unplugged.
  1293. /// ```
  1294. public var description: String {
  1295. switch self {
  1296. case .charging(let batteryLevel): return "Battery level: \(batteryLevel)%, device is plugged in."
  1297. case .full: return "Battery level: 100 % (Full), device is plugged in."
  1298. case .unplugged(let batteryLevel): return "Battery level: \(batteryLevel)%, device is unplugged."
  1299. }
  1300. }
  1301. }
  1302. /// The state of the battery
  1303. public var batteryState: BatteryState? {
  1304. guard isCurrent else { return nil }
  1305. return BatteryState()
  1306. }
  1307. /// Battery level ranges from 0 (fully discharged) to 100 (100% charged).
  1308. public var batteryLevel: Int? {
  1309. guard isCurrent else { return nil }
  1310. switch BatteryState() {
  1311. case .charging(let value): return value
  1312. case .full: return 100
  1313. case .unplugged(let value): return value
  1314. }
  1315. }
  1316. }
  1317. #endif
  1318. // MARK: Device.Batterystate: Comparable
  1319. #if os(iOS) || os(watchOS)
  1320. @available(iOS 8.0, watchOS 4.0, *)
  1321. extension Device.BatteryState: Comparable {
  1322. /// Tells if two battery states are equal.
  1323. ///
  1324. /// - parameter lhs: A battery state.
  1325. /// - parameter rhs: Another battery state.
  1326. ///
  1327. /// - returns: `true` iff they are equal, otherwise `false`
  1328. public static func == (lhs: Device.BatteryState, rhs: Device.BatteryState) -> Bool {
  1329. return lhs.description == rhs.description
  1330. }
  1331. /// Compares two battery states.
  1332. ///
  1333. /// - parameter lhs: A battery state.
  1334. /// - parameter rhs: Another battery state.
  1335. ///
  1336. /// - returns: `true` if rhs is `.Full`, `false` when lhs is `.Full` otherwise their battery level is compared.
  1337. public static func < (lhs: Device.BatteryState, rhs: Device.BatteryState) -> Bool {
  1338. switch (lhs, rhs) {
  1339. case (.full, _): return false // return false (even if both are `.Full` -> they are equal)
  1340. case (_, .full): return true // lhs is *not* `.Full`, rhs is
  1341. case let (.charging(lhsLevel), .charging(rhsLevel)): return lhsLevel < rhsLevel
  1342. case let (.charging(lhsLevel), .unplugged(rhsLevel)): return lhsLevel < rhsLevel
  1343. case let (.unplugged(lhsLevel), .charging(rhsLevel)): return lhsLevel < rhsLevel
  1344. case let (.unplugged(lhsLevel), .unplugged(rhsLevel)): return lhsLevel < rhsLevel
  1345. default: return false // compiler won't compile without it, though it cannot happen
  1346. }
  1347. }
  1348. }
  1349. #endif
  1350. #if os(iOS)
  1351. extension Device {
  1352. // MARK: Orientation
  1353. /**
  1354. This enum describes the state of the orientation.
  1355. - Landscape: The device is in Landscape Orientation
  1356. - Portrait: The device is in Portrait Orientation
  1357. */
  1358. public enum Orientation {
  1359. case landscape
  1360. case portrait
  1361. }
  1362. public var orientation: Orientation {
  1363. if UIDevice.current.orientation.isLandscape {
  1364. return .landscape
  1365. } else {
  1366. return .portrait
  1367. }
  1368. }
  1369. }
  1370. #endif
  1371. #if os(iOS)
  1372. // MARK: DiskSpace
  1373. extension Device {
  1374. /// Return the root url
  1375. ///
  1376. /// - returns: the NSHomeDirectory() url
  1377. private static let rootURL = URL(fileURLWithPath: NSHomeDirectory())
  1378. /// The volume’s total capacity in bytes.
  1379. public static var volumeTotalCapacity: Int? {
  1380. return (try? Device.rootURL.resourceValues(forKeys: [.volumeTotalCapacityKey]))?.volumeTotalCapacity
  1381. }
  1382. /// The volume’s available capacity in bytes.
  1383. public static var volumeAvailableCapacity: Int? {
  1384. return (try? rootURL.resourceValues(forKeys: [.volumeAvailableCapacityKey]))?.volumeAvailableCapacity
  1385. }
  1386. /// The volume’s available capacity in bytes for storing important resources.
  1387. @available(iOS 11.0, *)
  1388. public static var volumeAvailableCapacityForImportantUsage: Int64? {
  1389. return (try? rootURL.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey]))?.volumeAvailableCapacityForImportantUsage
  1390. }
  1391. /// The volume’s available capacity in bytes for storing nonessential resources.
  1392. @available(iOS 11.0, *)
  1393. public static var volumeAvailableCapacityForOpportunisticUsage: Int64? { //swiftlint:disable:this identifier_name
  1394. return (try? rootURL.resourceValues(forKeys: [.volumeAvailableCapacityForOpportunisticUsageKey]))?.volumeAvailableCapacityForOpportunisticUsage
  1395. }
  1396. /// All volumes capacity information in bytes.
  1397. @available(iOS 11.0, *)
  1398. public static var volumes: [URLResourceKey: Int64]? {
  1399. do {
  1400. let values = try rootURL.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey,
  1401. .volumeAvailableCapacityKey,
  1402. .volumeAvailableCapacityForOpportunisticUsageKey,
  1403. .volumeTotalCapacityKey
  1404. ])
  1405. return values.allValues.mapValues {
  1406. if let int = $0 as? Int64 {
  1407. return int
  1408. }
  1409. if let int = $0 as? Int {
  1410. return Int64(int)
  1411. }
  1412. return 0
  1413. }
  1414. } catch {
  1415. return nil
  1416. }
  1417. }
  1418. }
  1419. #endif
  1420. #if os(iOS)
  1421. // MARK: Apple Pencil
  1422. extension Device {
  1423. /**
  1424. This option set describes the current Apple Pencils
  1425. - firstGeneration: 1st Generation Apple Pencil
  1426. - secondGeneration: 2nd Generation Apple Pencil
  1427. */
  1428. public struct ApplePencilSupport: OptionSet {
  1429. public var rawValue: UInt
  1430. public init(rawValue: UInt) {
  1431. self.rawValue = rawValue
  1432. }
  1433. public static let firstGeneration = ApplePencilSupport(rawValue: 0x01)
  1434. public static let secondGeneration = ApplePencilSupport(rawValue: 0x02)
  1435. }
  1436. /// All Apple Pencil Capable Devices
  1437. public static var allApplePencilCapableDevices: [Device] {
  1438. return [.iPad6, .iPadAir3, .iPad7, .iPad8, .iPadAir4, .iPadMini5, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4]
  1439. }
  1440. /// Returns supported version of the Apple Pencil
  1441. public var applePencilSupport: ApplePencilSupport {
  1442. switch self {
  1443. case .iPad6: return .firstGeneration
  1444. case .iPadAir3: return .firstGeneration
  1445. case .iPad7: return .firstGeneration
  1446. case .iPad8: return .firstGeneration
  1447. case .iPadMini5: return .firstGeneration
  1448. case .iPadPro9Inch: return .firstGeneration
  1449. case .iPadPro12Inch: return .firstGeneration
  1450. case .iPadPro12Inch2: return .firstGeneration
  1451. case .iPadPro10Inch: return .firstGeneration
  1452. case .iPadAir4: return .secondGeneration
  1453. case .iPadPro11Inch: return .secondGeneration
  1454. case .iPadPro12Inch3: return .secondGeneration
  1455. case .iPadPro11Inch2: return .secondGeneration
  1456. case .iPadPro12Inch4: return .secondGeneration
  1457. case .simulator(let model): return model.applePencilSupport
  1458. default: return []
  1459. }
  1460. }
  1461. }
  1462. #endif
  1463. #if os(iOS)
  1464. // MARK: Cameras
  1465. extension Device {
  1466. public enum CameraType {
  1467. @available(*, deprecated, renamed: "wide")
  1468. case normal
  1469. case wide
  1470. case telephoto
  1471. case ultraWide
  1472. }
  1473. /// Returns an array of the types of cameras the device has
  1474. public var cameras: [CameraType] {
  1475. switch self {
  1476. case .iPodTouch5: return [.wide]
  1477. case .iPodTouch6: return [.wide]
  1478. case .iPodTouch7: return [.wide]
  1479. case .iPhone4: return [.wide]
  1480. case .iPhone4s: return [.wide]
  1481. case .iPhone5: return [.wide]
  1482. case .iPhone5c: return [.wide]
  1483. case .iPhone5s: return [.wide]
  1484. case .iPhone6: return [.wide]
  1485. case .iPhone6Plus: return [.wide]
  1486. case .iPhone6s: return [.wide]
  1487. case .iPhone6sPlus: return [.wide]
  1488. case .iPhone7: return [.wide]
  1489. case .iPhoneSE: return [.wide]
  1490. case .iPhone8: return [.wide]
  1491. case .iPhoneXR: return [.wide]
  1492. case .iPhoneSE2: return [.wide]
  1493. case .iPad2: return [.wide]
  1494. case .iPad3: return [.wide]
  1495. case .iPad4: return [.wide]
  1496. case .iPadAir: return [.wide]
  1497. case .iPadAir2: return [.wide]
  1498. case .iPad5: return [.wide]
  1499. case .iPad6: return [.wide]
  1500. case .iPadAir3: return [.wide]
  1501. case .iPad7: return [.wide]
  1502. case .iPad8: return [.wide]
  1503. case .iPadAir4: return [.wide]
  1504. case .iPadMini: return [.wide]
  1505. case .iPadMini2: return [.wide]
  1506. case .iPadMini3: return [.wide]
  1507. case .iPadMini4: return [.wide]
  1508. case .iPadMini5: return [.wide]
  1509. case .iPadPro9Inch: return [.wide]
  1510. case .iPadPro12Inch: return [.wide]
  1511. case .iPadPro12Inch2: return [.wide]
  1512. case .iPadPro10Inch: return [.wide]
  1513. case .iPadPro11Inch: return [.wide]
  1514. case .iPadPro12Inch3: return [.wide]
  1515. case .iPhone7Plus: return [.wide, .telephoto]
  1516. case .iPhone8Plus: return [.wide, .telephoto]
  1517. case .iPhoneX: return [.wide, .telephoto]
  1518. case .iPhoneXS: return [.wide, .telephoto]
  1519. case .iPhoneXSMax: return [.wide, .telephoto]
  1520. case .iPhone11: return [.wide, .ultraWide]
  1521. case .iPhone12: return [.wide, .ultraWide]
  1522. case .iPhone12Mini: return [.wide, .ultraWide]
  1523. case .iPadPro11Inch2: return [.wide, .ultraWide]
  1524. case .iPadPro12Inch4: return [.wide, .ultraWide]
  1525. case .iPhone11Pro: return [.wide, .telephoto, .ultraWide]
  1526. case .iPhone11ProMax: return [.wide, .telephoto, .ultraWide]
  1527. case .iPhone12Pro: return [.wide, .telephoto, .ultraWide]
  1528. case .iPhone12ProMax: return [.wide, .telephoto, .ultraWide]
  1529. default: return []
  1530. }
  1531. }
  1532. /// All devices that feature a camera
  1533. public static var allDevicesWithCamera: [Device] {
  1534. 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, .iPhoneSE2, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax, .iPad2, .iPad3, .iPad4, .iPadAir, .iPadAir2, .iPad5, .iPad6, .iPadAir3, .iPad7, .iPad8, .iPadAir4, .iPadMini, .iPadMini2, .iPadMini3, .iPadMini4, .iPadMini5, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4]
  1535. }
  1536. /// All devices that feature a normal camera
  1537. @available(*, deprecated, renamed: "allDevicesWithWideCamera")
  1538. public static var allDevicesWithNormalCamera: [Device] {
  1539. return Device.allDevicesWithWideCamera
  1540. }
  1541. /// All devices that feature a wide camera
  1542. public static var allDevicesWithWideCamera: [Device] {
  1543. 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, .iPhoneSE2, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax, .iPad2, .iPad3, .iPad4, .iPadAir, .iPadAir2, .iPad5, .iPad6, .iPadAir3, .iPad7, .iPad8, .iPadAir4, .iPadMini, .iPadMini2, .iPadMini3, .iPadMini4, .iPadMini5, .iPadPro9Inch, .iPadPro12Inch, .iPadPro12Inch2, .iPadPro10Inch, .iPadPro11Inch, .iPadPro12Inch3, .iPadPro11Inch2, .iPadPro12Inch4]
  1544. }
  1545. /// All devices that feature a telephoto camera
  1546. public static var allDevicesWithTelephotoCamera: [Device] {
  1547. return [.iPhone7Plus, .iPhone8Plus, .iPhoneX, .iPhoneXS, .iPhoneXSMax, .iPhone11Pro, .iPhone11ProMax, .iPhone12Pro, .iPhone12ProMax]
  1548. }
  1549. /// All devices that feature an ultra wide camera
  1550. public static var allDevicesWithUltraWideCamera: [Device] {
  1551. return [.iPhone11, .iPhone11Pro, .iPhone11ProMax, .iPhone12, .iPhone12Mini, .iPhone12Pro, .iPhone12ProMax, .iPadPro11Inch2, .iPadPro12Inch4]
  1552. }
  1553. /// Returns whether or not the current device has a camera
  1554. public var hasCamera: Bool {
  1555. return !self.cameras.isEmpty
  1556. }
  1557. /// Returns whether or not the current device has a normal camera
  1558. @available(*, deprecated, renamed: "hasWideCamera")
  1559. public var hasNormalCamera: Bool {
  1560. return self.hasWideCamera
  1561. }
  1562. /// Returns whether or not the current device has a wide camera
  1563. public var hasWideCamera: Bool {
  1564. return self.cameras.contains(.wide)
  1565. }
  1566. /// Returns whether or not the current device has a telephoto camera
  1567. public var hasTelephotoCamera: Bool {
  1568. return self.cameras.contains(.telephoto)
  1569. }
  1570. /// Returns whether or not the current device has an ultra wide camera
  1571. public var hasUltraWideCamera: Bool {
  1572. return self.cameras.contains(.ultraWide)
  1573. }
  1574. }
  1575. #endif