├── .github
└── workflows
│ └── swift.yml
├── .swiftpm
└── xcode
│ ├── package.xcworkspace
│ └── xcuserdata
│ │ └── anton.paliakou.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
│ ├── xcshareddata
│ └── xcschemes
│ │ └── PreviewDevice.xcscheme
│ └── xcuserdata
│ └── anton.paliakou.xcuserdatad
│ └── xcschemes
│ └── xcschememanagement.plist
├── Assets
└── Iphone12ColorSchemes.png
├── Documentation
└── Usage.md
├── LICENSE
├── Package.swift
├── PreviewDevice.podspec
├── README.md
├── Sources
└── PreviewDevice
│ ├── CocoaPreivew
│ ├── NSViewControllerPreview.swift
│ └── NSViewPreview.swift
│ ├── Device.swift
│ ├── UIKitPreview
│ ├── UIViewControllerPreview.swift
│ └── UIViewPreview.swift
│ └── View+PreviewDevice.swift
└── Tests
└── PreviewDeviceTests
├── DeviceAppleTVTests.swift
├── DeviceIpadTests.swift
├── DeviceIphoneTests.swift
├── DeviceIpodTests.swift
├── DeviceMacTests.swift
└── DeviceWatchTests.swift
/.github/workflows/swift.yml:
--------------------------------------------------------------------------------
1 | name: Swift
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: macos-15
13 |
14 | steps:
15 | - uses: actions/checkout@v2
16 | - name: Build
17 | run: swift build -v
18 | - name: Run tests
19 | run: swift test -v
20 |
21 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/xcuserdata/anton.paliakou.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Toni77777/PreviewDevice/2325173fd1daf063ac876819f99a890eb4d91a6a/.swiftpm/xcode/package.xcworkspace/xcuserdata/anton.paliakou.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/.swiftpm/xcode/xcshareddata/xcschemes/PreviewDevice.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
48 |
54 |
55 |
56 |
57 |
58 |
68 |
69 |
75 |
76 |
82 |
83 |
84 |
85 |
87 |
88 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/xcuserdata/anton.paliakou.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | PreviewDevice.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | PreviewDevice
16 |
17 | primary
18 |
19 |
20 | PreviewDeviceTests
21 |
22 | primary
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Assets/Iphone12ColorSchemes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Toni77777/PreviewDevice/2325173fd1daf063ac876819f99a890eb4d91a6a/Assets/Iphone12ColorSchemes.png
--------------------------------------------------------------------------------
/Documentation/Usage.md:
--------------------------------------------------------------------------------
1 | In Progress
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Anton Paliakov
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "PreviewDevice",
8 | platforms: [.iOS(.v13), .tvOS(.v13), .watchOS(.v6), .macOS(.v10_15)],
9 | products: [
10 | // Products define the executables and libraries a package produces, and make them visible to other packages.
11 | .library(
12 | name: "PreviewDevice",
13 | targets: ["PreviewDevice"]),
14 | ],
15 | dependencies: [
16 | // Dependencies declare other packages that this package depends on.
17 | // .package(url: /* package url */, from: "1.0.0"),
18 | ],
19 | targets: [
20 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
21 | // Targets can depend on other targets in this package, and on products in packages this package depends on.
22 | .target(
23 | name: "PreviewDevice",
24 | dependencies: []),
25 | .testTarget(
26 | name: "PreviewDeviceTests",
27 | dependencies: ["PreviewDevice"]),
28 | ]
29 | )
30 |
--------------------------------------------------------------------------------
/PreviewDevice.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |spec|
2 | spec.name = "PreviewDevice"
3 | spec.version = "0.9.0"
4 | spec.summary = "PreviewDevice - library with elegant syntax for Preview Device in SwiftUI"
5 | spec.description = "PreviewDevice - is a sugar wrapper around the Apple Preview Device. SwiftUI"
6 | spec.homepage = "https://github.com/Toni77777/PreviewDevice"
7 | spec.license = "MIT"
8 | spec.author = { "Anton Paliakov" => "toxa95401@gmail.com" }
9 | spec.ios.deployment_target = "13.0"
10 | spec.osx.deployment_target = "10.15"
11 | spec.watchos.deployment_target = "6.0"
12 | spec.tvos.deployment_target = "13.0"
13 | spec.source = { :git => "https://github.com/Toni77777/PreviewDevice.git", :tag => "#{spec.version}" }
14 | spec.source_files = "Sources/PreviewDevice/*.swift"
15 | spec.swift_version = "4.2"
16 | end
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PreviewDevice
2 | 
3 | [](https://cocoapods.org/pods/PreviewDevice)
4 | 
5 | 
6 | [](https://twitter.com/Toni777772)
7 |
8 | ## Requirements
9 |
10 | * Dev environment: Xcode 13+, macOS 12+
11 | * iOS 13.0+, macOS 10.15+, Mac Catalyst 13.0+, tvOS 13.0+, watchOS 6.0+
12 |
13 | ## Usage
14 |
15 | Example:
16 |
17 | ```swift
18 | import PreviewDevice
19 |
20 | struct ContentView_Previews: PreviewProvider {
21 |
22 | static var previews: some View {
23 | ContentView()
24 | .previewDevice(device: .iphone13, colorSchemes: ColorScheme.allCases)
25 | }
26 | }
27 | ```
28 |
29 | Result
30 |
31 |

32 |
33 |
34 | ### Preview on device
35 |
36 | ```swift
37 | .previewDevice(device: .iphone12)
38 | ```
39 |
40 |
41 | ### Preview on devices
42 |
43 | ```swift
44 | .previewDevices(device: [.iphone8, .iphone11Pro .iphone12, .iphone12ProMax])
45 | ```
46 |
47 | ### Preview on device with color scheme (light, dark)
48 |
49 | ```swift
50 | .previewDevice(device: .iphone12, colorScheme: .light)
51 | ```
52 |
53 | ### Preview on device with ColorSchemes
54 |
55 | ```swift
56 | .previewDevice(device: .iphone12, colorScheme: [.light, .dark])
57 | ```
58 |
59 | ### Preview on device with orientation (InterfaceOrientation)
60 |
61 | ```swift
62 | .previewDevice(device: .iphone12, orientation: .portrait)
63 | ```
64 |
65 | ### Preview on device with orientations
66 |
67 | ```swift
68 | .previewDevice(device: .iphone12, orientations: [.portrait, .landscapeLeft, .landscapeRight])
69 | ```
70 |
71 | ### Preview on device with orientation and color schemes
72 |
73 | ```swift
74 | .previewDevice(device: .iphone12, orientation: .portrait, colorSchemes: [.light, .dark])
75 | ```
76 |
77 | ## Installation
78 |
79 | ### [CocoaPods](https://guides.cocoapods.org/using/using-cocoapods.html)
80 | Specify next line in Podfile:
81 |
82 | ```ruby
83 | pod PreviewDevice
84 | ```
85 |
86 | ### [Swift Package Manager](https://github.com/apple/swift-package-manager)
87 |
88 | Open Xcode, File -> Swift Packages -> Add Packages.. and paste library git url:
89 |
90 | ```
91 | https://github.com/Toni77777/PreviewDevice.git
92 | ```
93 |
94 | ## Articles
95 | [Meet PreviewDevice 0.7.0](https://dev.to/toni777772/meet-previewdevice-0-7-0-1dpg)
96 |
97 | [What's new in PreviewDevice 0.8.0](https://dev.to/toni777772/what-s-new-in-previewdevice-0-8-0-5dc0)
98 |
99 | ## License
100 | PreviewDevice is released under the MIT license.
101 |
--------------------------------------------------------------------------------
/Sources/PreviewDevice/CocoaPreivew/NSViewControllerPreview.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSViewControllerPreview.swift
3 | //
4 | //
5 | // Created by Anton Paliakou on 10/15/21.
6 | //
7 |
8 | #if canImport(AppKit) && canImport(SwiftUI)
9 | import AppKit
10 | import SwiftUI
11 |
12 | public struct NSViewControllerPreview: NSViewControllerRepresentable {
13 |
14 | // MARK: - Properties
15 |
16 | private let viewController: NSViewController
17 |
18 | // MARK: - Init
19 |
20 | public init(viewController: NSViewController) {
21 | self.viewController = viewController
22 | }
23 |
24 | // MARK: - NSViewControllerRepresentable
25 |
26 | public func makeNSViewController(context: Context) -> NSViewController {
27 | viewController
28 | }
29 |
30 | public func updateNSViewController(_ nsViewController: NSViewController, context: Context) {
31 | }
32 | }
33 | #endif
34 |
--------------------------------------------------------------------------------
/Sources/PreviewDevice/CocoaPreivew/NSViewPreview.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSViewPreview.swift
3 | //
4 | //
5 | // Created by Anton Paliakou on 10/16/21.
6 | //
7 |
8 | #if canImport(AppKit) && canImport(SwiftUI)
9 | import AppKit
10 | import SwiftUI
11 |
12 | public struct NSViewPreview: NSViewRepresentable {
13 |
14 | // MARK: - Properties
15 |
16 | private let view: NSView
17 |
18 | // MARK: - Init
19 |
20 | public init(view: NSView) {
21 | self.view = view
22 | }
23 |
24 | // MARK: - NSViewRepresentable
25 |
26 | public func makeNSView(context: Context) -> NSView {
27 | view
28 | }
29 |
30 | public func updateNSView(_ nsView: NSView, context: Context) {
31 | }
32 | }
33 | #endif
34 |
--------------------------------------------------------------------------------
/Sources/PreviewDevice/Device.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Device.swift
3 | // PreviewDevice
4 | //
5 | //
6 | // Created by Anton Paliakou on 8/26/21.
7 | //
8 |
9 | import Foundation
10 |
11 | public enum Device: String {
12 |
13 | // MARK: - iPhone
14 |
15 | case iphone6Plus = "iPhone 6 Plus"
16 | case iphone6 = "iPhone 6"
17 | case iphone6s = "iPhone 6s"
18 | case iphone6sPlus = "iPhone 6s Plus"
19 | case iphoneSE_1Gen = "iPhone SE (1st generation)"
20 | case iphone7 = "iPhone 7"
21 | case iphone7Plus = "iPhone 7 Plus"
22 | case iphone8 = "iPhone 8"
23 | case iphone8Plus = "iPhone 8 Plus"
24 | case iphoneX = "iPhone X"
25 | case iphoneXs = "iPhone Xs"
26 | case iphoneXsMax = "iPhone Xs Max"
27 | case iphoneXr = "iPhone Xʀ"
28 | case iphone11 = "iPhone 11"
29 | case iphone11Pro = "iPhone 11 Pro"
30 | case iphone11ProMax = "iPhone 11 Pro Max"
31 | case iphoneSE_2Gen = "iPhone SE (2nd generation)"
32 | case iphone12Mini = "iPhone 12 mini"
33 | case iphone12 = "iPhone 12"
34 | case iphone12Pro = "iPhone 12 Pro"
35 | case iphone12ProMax = "iPhone 12 Pro Max"
36 | case iphone13Pro = "iPhone 13 Pro"
37 | case iphone13ProMax = "iPhone 13 Pro Max"
38 | case iphone13Mini = "iPhone 13 mini"
39 | case iphone13 = "iPhone 13"
40 | case iphoneSE_3Gen = "iPhone SE (3rd generation)"
41 | case iphone14 = "iPhone 14"
42 | case iphone14Plus = "iPhone 14 Plus"
43 | case iphone14Pro = "iPhone 14 Pro"
44 | case iphone14ProMax = "iPhone 14 Pro Max"
45 | case iphone15 = "iPhone 15"
46 | case iphone15Plus = "iPhone 15 Plus"
47 | case iphone15Pro = "iPhone 15 Pro"
48 | case iphone15ProMax = "iPhone 15 Pro Max"
49 | case iphone16 = "iPhone 16"
50 | case iphone16Plus = "iPhone 16 Plus"
51 | case iphone16Pro = "iPhone 16 Pro"
52 | case iphone16ProMax = "iPhone 16 Pro Max"
53 |
54 | // MARK: - iPad
55 |
56 | case ipad2 = "iPad 2"
57 | case ipadRetina = "iPad Retina"
58 | case ipadAir = "iPad Air"
59 | case ipadMini2 = "iPad mini 2"
60 | case ipadMini3 = "iPad mini 3"
61 | case ipadMini4 = "iPad mini 4"
62 | case ipadMini5 = "iPad mini (5th generation)"
63 | case ipadMini6 = "iPad mini (6th generation)"
64 | case ipadAir2 = "iPad Air 2"
65 | case ipadPro9_7inch = "iPad Pro (9.7-inch)"
66 | case ipadPro12_9inch = "iPad Pro (12.9-inch)"
67 | case ipad_5Gen = "iPad (5th generation)"
68 | case ipadPro12_9inch_2Gen = "iPad Pro (12.9-inch) (2nd generation)"
69 | case ipadPro10_5inch = "iPad Pro (10.5-inch)"
70 | case ipad_6Gen = "iPad (6th generation)"
71 | case ipad_7Gen = "iPad (7th generation)"
72 | case ipad_8Gen = "iPad (8th generation)"
73 | case ipad_9Gen = "iPad (9th generation)"
74 | case ipadPro11inch_1Gen = "iPad Pro (11-inch) (1st generation)"
75 | case ipadPro12_9inch_3Gen = "iPad Pro (12.9-inch) (3rd generation)"
76 | case ipadPro11inch_2Gen = "iPad Pro (11-inch) (2nd generation)"
77 | case ipadPro12_9inch_4Gen = "iPad Pro (12.9-inch) (4th generation)"
78 | case ipadAir_3Gen = "iPad Air (3rd generation)"
79 | case ipadAir_4Gen = "iPad Air (4th generation)"
80 | case ipadPro11inch_3Gen = "iPad Pro (11-inch) (3rd generation)"
81 | case ipadPro12_9inch_5Gen = "iPad Pro (12.9-inch) (5th generation)"
82 | case ipadAir_5Gen = "iPad Air (5th generation)"
83 |
84 |
85 | // MARK: - iPod
86 |
87 | case ipod7Gen = "iPod touch (7th generation)"
88 |
89 | // MARK: - Mac
90 |
91 | case mac = "Mac"
92 | case macCatalyst = "Mac Catalyst"
93 |
94 | // MARK: - Apple TV
95 |
96 | case appleTV = "Apple TV"
97 | case appleTV4K = "Apple TV 4K"
98 | case appleTV4K1080p = "Apple TV 4K (at 1080p)"
99 | case appleTV4K_2Gen = "Apple TV 4K (2nd generation)"
100 | case appleTV4K1080p_2Gen = "Apple TV 4K (at 1080p) (2nd generation)"
101 |
102 | // MARK: - Apple Watch
103 |
104 | case watch_38mm = "Apple Watch (38mm)"
105 | case watch_42mm = "Apple Watch (42mm)"
106 | case watchSeries2_38mm = "Apple Watch Series 2 (38mm)"
107 | case watchSeries2_42mm = "Apple Watch Series 2 (42mm)"
108 | case watchSeries3_38mm = "Apple Watch Series 3 (38mm)"
109 | case watchSeries3_42mm = "Apple Watch Series 3 (42mm)"
110 | case watchSeries4_40mm = "Apple Watch Series 4 (40mm)"
111 | case watchSeries4_44mm = "Apple Watch Series 4 (44mm)"
112 | case watchSeries5_40mm = "Apple Watch Series 5 (40mm)"
113 | case watchSeries5_44mm = "Apple Watch Series 5 (44mm)"
114 | case watchSE_40mm = "Apple Watch SE (40mm)"
115 | case watchSE_44mm = "Apple Watch SE (44mm)"
116 | case watchSeries6_40mm = "Apple Watch Series 6 (40mm)"
117 | case watchSeries6_44mm = "Apple Watch Series 6 (44mm)"
118 | case watchSeries7_41mm = "Apple Watch Series 7 (41mm)"
119 | case watchSeries7_45mm = "Apple Watch Series 7 (45mm)"
120 | case watchSE_2Gen_40mm = "Apple Watch SE (40mm) (2nd generation)"
121 | case watchSE_2Gen_44mm = "Apple Watch SE (44mm) (2nd generation)"
122 | case watchSeries8_41mm = "Apple Watch Series 8 (41mm)"
123 | case watchSeries8_45mm = "Apple Watch Series 8 (45mm)"
124 | case watchUltra_49mm = "Apple Watch Ultra (49mm)"
125 | }
126 |
--------------------------------------------------------------------------------
/Sources/PreviewDevice/UIKitPreview/UIViewControllerPreview.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewControllerPreview.swift
3 | //
4 | //
5 | // Created by Anton Paliakou on 10/15/21.
6 | //
7 |
8 | #if canImport(UIKit) && canImport(SwiftUI)
9 | import SwiftUI
10 | import UIKit
11 |
12 | public struct UIViewControllerPreview: UIViewControllerRepresentable {
13 |
14 | // MARK: - Properties
15 |
16 | private let viewController: UIViewController
17 |
18 | // MARK: - Init
19 |
20 | public init(viewController: UIViewController) {
21 | self.viewController = viewController
22 | }
23 |
24 | // MARK: - UIViewControllerRepresentable
25 |
26 | public func makeUIViewController(context: Context) -> UIViewController {
27 | viewController
28 | }
29 |
30 | public func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
31 | }
32 | }
33 |
34 | #endif
35 |
--------------------------------------------------------------------------------
/Sources/PreviewDevice/UIKitPreview/UIViewPreview.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewPreview.swift
3 | //
4 | //
5 | // Created by Anton Paliakou on 10/15/21.
6 | //
7 |
8 | #if canImport(UIKit) && canImport(SwiftUI)
9 | import SwiftUI
10 | import UIKit
11 |
12 | public struct UIViewPreview: UIViewRepresentable {
13 |
14 | // MARK: - Properties
15 |
16 | private let view: UIView
17 |
18 | // MARK: - Init
19 |
20 | public init(view: UIView) {
21 | self.view = view
22 | }
23 |
24 | // MARK: - UIViewRepresentable
25 |
26 | public func makeUIView(context: Context) -> UIViewType {
27 | self.view
28 | }
29 |
30 | public func updateUIView(_ uiView: UIView, context: Context) {
31 | }
32 | }
33 |
34 | #endif
35 |
--------------------------------------------------------------------------------
/Sources/PreviewDevice/View+PreviewDevice.swift:
--------------------------------------------------------------------------------
1 | //
2 | // View+PreviewDevice.swift
3 | // PreviewDevice
4 | //
5 | // Created by Anton Paliakou on 8/26/21.
6 | //
7 |
8 | #if canImport(SwiftUI)
9 | import SwiftUI
10 |
11 | @available(iOS 13.0, OSX 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *)
12 | public extension View {
13 |
14 | func previewDevice(device: Device) -> some View {
15 | previewDevice(PreviewDevice(rawValue: device.rawValue))
16 | .previewDisplayName(device.rawValue)
17 | }
18 |
19 | func previewDevices(devices: [Device]) -> some View {
20 | ForEach(devices, id: \.self) { device in
21 | previewDevice(device: device)
22 | }
23 | }
24 | }
25 |
26 | @available(iOS 13.0, macOS 11.0, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *)
27 | public extension View {
28 |
29 | func previewDevice(device: Device, colorScheme: ColorScheme) -> some View {
30 | previewDevice(device: device)
31 | .preferredColorScheme(colorScheme)
32 | }
33 |
34 | func previewDevice(device: Device, colorSchemes: [ColorScheme]) -> some View {
35 | ForEach(0.. some View {
46 | previewDevice(device: device)
47 | .previewInterfaceOrientation(orientation)
48 | }
49 |
50 | func previewDevice(device: Device, orientations: [InterfaceOrientation]) -> some View {
51 | ForEach(0.. some View {
58 | ForEach(0..