Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// swift-tools-version:5.3
// swift-tools-version:5.7
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "ImagePickerView",
platforms: [
.iOS(.v14)
.iOS(.v14), .macOS(.v13)
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
![swift v5.3](https://img.shields.io/badge/swift-v5.3-orange.svg)
![platform iOS](https://img.shields.io/badge/platform-iOS-blue.svg)
![deployment target iOS 14](https://img.shields.io/badge/deployment%20target-iOS%2014-blueviolet)
![platform macOS](https://img.shields.io/badge/platform-macOS-blue.svg)
![deployment target macOS 13](https://img.shields.io/badge/deployment%20target-macOS%2013-brightgreen)

**ImagePickerView** is a lightweight library which brings `PHPickerViewController` / `UIImagePickerController` to `SwiftUI`.

Expand All @@ -16,7 +18,7 @@ https://github.com/rebeloper/ImagePickerView.git
Download and include the `ImagePickerView` folder and files in your codebase.

### 📲 Requirements
- iOS 14+
- iOS 14+ / macOS 13+
- Swift 5.3+

## 👉 Import
Expand All @@ -30,8 +32,8 @@ import ImagePickerView
## 🧳 Features

Here's the list of the awesome features `ImagePickerView` has:
- [X] use `PHPickerViewController` as a `View` in `SwiftUI` projects (recommended, introduced in `iOS14`)
- [X] use `UIImagePickerController` as a `View` in `SwiftUI` projects (not-recommended; use only for single image picking and when you want to enable editing)
- [X] use `PHPickerViewController` as a `View` in `SwiftUI` projects (recommended, introduced in `iOS14`/`macOS13`)
- [X] use `UIImagePickerController` as a `View` in `SwiftUI` projects (iOS-only, not-recommended; use only for single image picking and when you want to enable editing)
- [X] set `filter` and `selectionLimit` in `ImagePickerView`
- [X] `didCancel`, `didSelect` and `didFail` delegate callbacks for `ImagePickerView`
- [X] set `allowsEditing` in `UIImagePickerView`
Expand Down
26 changes: 17 additions & 9 deletions Sources/ImagePickerView/ImagePickerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,20 @@
//

import SwiftUI
import UIKit
import PhotosUI

public struct ImagePickerView: UIViewControllerRepresentable {
#if canImport(UIKit)
import UIKit
public typealias PHImage = UIImage
#elseif canImport(AppKit)
import AppKit
public typealias PHImage = NSImage
#endif


public struct ImagePickerView: ViewControllerRepresentable {

public typealias UIViewControllerType = PHPickerViewController
public typealias ViewControllerType = PHPickerViewController

public init(filter: PHPickerFilter = .images, selectionLimit: Int = 1, delegate: PHPickerViewControllerDelegate) {
self.filter = filter
Expand All @@ -23,7 +31,7 @@ public struct ImagePickerView: UIViewControllerRepresentable {
private let selectionLimit: Int
private let delegate: PHPickerViewControllerDelegate

public func makeUIViewController(context: Context) -> PHPickerViewController {
public func makeViewController(context: Context) -> PHPickerViewController {
var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
configuration.filter = filter
configuration.selectionLimit = selectionLimit
Expand All @@ -33,7 +41,7 @@ public struct ImagePickerView: UIViewControllerRepresentable {
return controller
}

public func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) { }
public func updateViewController(_ viewController: PHPickerViewController, context: Context) { }
}

extension ImagePickerView {
Expand All @@ -60,12 +68,12 @@ extension ImagePickerView {
var images = [ImagePickerResult.SelectedImage]()
for i in 0..<results.count {
let result = results[i]
if result.itemProvider.canLoadObject(ofClass: UIImage.self) {
result.itemProvider.loadObject(ofClass: UIImage.self) { newImage, error in
if result.itemProvider.canLoadObject(ofClass: PHImage.self) {
result.itemProvider.loadObject(ofClass: PHImage.self) { newImage, error in
if let error = error {
self.isPresented = false
self.didFail(ImagePickerError(picker: picker, error: error))
} else if let image = newImage as? UIImage {
} else if let image = newImage as? PHImage {
images.append(.init(index: i, image: image))
}
if images.count == results.count {
Expand Down Expand Up @@ -94,7 +102,7 @@ public struct ImagePickerResult {

public struct SelectedImage {
public let index: Int
public let image: UIImage
public let image: PHImage
}
}

Expand Down
2 changes: 2 additions & 0 deletions Sources/ImagePickerView/UIImagePickerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

import SwiftUI
#if canImport(UIKit)
import UIKit

@available(iOS 13.0, *)
Expand Down Expand Up @@ -79,3 +80,4 @@ public struct UIImagePickerResult {
public let picker: UIImagePickerController
public let image: UIImage
}
#endif
41 changes: 41 additions & 0 deletions Sources/ImagePickerView/ViewControllerRepresentable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import SwiftUI

#if canImport(UIKit)
import UIKit
public typealias PlatformViewControllerRepresentable = UIViewControllerRepresentable
#elseif canImport(AppKit)
import AppKit
public typealias PlatformViewControllerRepresentable = NSViewControllerRepresentable
#endif

/// Provides either `UIViewControllerRepresentable` or `NSViewControllerRepresentable` conformance depending on the target platform;
/// Roughly based on https://gist.github.com/insidegui/97d821ca933c8627e7f614bc1d6b4983
public protocol ViewControllerRepresentable: PlatformViewControllerRepresentable {
associatedtype ViewControllerType

func makeViewController(context: Context) -> ViewControllerType
func updateViewController(_ viewController: ViewControllerType, context: Context)
}


#if canImport(UIKit)
public extension ViewControllerRepresentable where ViewControllerType == UIViewControllerType {
func makeUIViewController(context: Context) -> UIViewControllerType {
self.makeViewController(context: context)
}

func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
self.updateViewController(uiViewController, context: context)
}
}
#elseif canImport(AppKit)
public extension ViewControllerRepresentable where ViewControllerType == NSViewControllerType {
func makeNSViewController(context: Context) -> NSViewControllerType {
self.makeViewController(context: context)
}

func updateNSViewController(_ nsViewController: NSViewControllerType, context: Context) {
self.updateViewController(nsViewController, context: context)
}
}
#endif