Skip to content

Commit

Permalink
Merge pull request #69 from GSM-MSG/68-image-or-camera-picker
Browse files Browse the repository at this point in the history
🔀 :: 이미지 & 카메라 Picker
  • Loading branch information
baekteun authored May 16, 2023
2 parents 1292f80 + 5681f08 commit 95130fe
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 0 deletions.
92 changes: 92 additions & 0 deletions Projects/Core/DesignSystem/Sources/CameraPicker/CameraPicker.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import SwiftUI
import Photos
import UIKit

public extension View {
func cameraPicker(
isShow: Binding<Bool>,
pickedImageResult: Binding<PickedImageResult?>
) -> some View {
self.fullScreenCover(isPresented: isShow) {
CameraPicker(pickedImageResult: pickedImageResult, isPresented: isShow)
}
}
}

struct CameraPicker: UIViewControllerRepresentable {
var sourceType: UIImagePickerController.SourceType = .camera
@Binding var pickedImageResult: PickedImageResult?
@Binding var isPresented: Bool

init(pickedImageResult: Binding<PickedImageResult?>, isPresented: Binding<Bool>) {
self._pickedImageResult = pickedImageResult
self._isPresented = isPresented
}

func makeCoordinator() -> ImagePickerViewCoordinator {
return ImagePickerViewCoordinator(pickedImageResult: $pickedImageResult, isPresented: $isPresented)
}

func makeUIViewController(context: Context) -> UIImagePickerController {
let pickerController = UIImagePickerController()
pickerController.sourceType = .camera
pickerController.delegate = context.coordinator
pickerController.allowsEditing = true
pickerController.mediaTypes = ["public.movie", "public.image"]
pickerController.cameraFlashMode = .auto
return pickerController
}

func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {}
}

final class ImagePickerViewCoordinator:
NSObject,
UINavigationControllerDelegate,
UIImagePickerControllerDelegate {

@Binding var pickedImageResult: PickedImageResult?
@Binding var isPresented: Bool

init(pickedImageResult: Binding<PickedImageResult?>, isPresented: Binding<Bool>) {
self._pickedImageResult = pickedImageResult
self._isPresented = isPresented
}

func imagePickerController(
_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]
) {
let filename: String
if let asset = info[.phAsset] as? PHAsset, let fileName = asset.value(forKey: "filename") as? String {
filename = fileName
} else if let url = info[.imageURL] as? URL {
filename = url.lastPathComponent
} else if let url = info[.mediaURL] as? URL {
filename = url.lastPathComponent
} else {
filename = ""
}

if let image = info[.editedImage] as? UIImage {
let pickedImageResult = PickedImageResult(fileName: filename, uiImage: image)
self.pickedImageResult = pickedImageResult
} else if let image = info[.originalImage] as? UIImage {
let pickedImageResult = PickedImageResult(fileName: filename, uiImage: image)
self.pickedImageResult = pickedImageResult
} else if let mediaURL = info[.mediaURL] as? URL {
Task(priority: .userInitiated) {
let (data, _) = try await URLSession.shared.data(from: mediaURL)
guard let image = UIImage(data: data) else { return }
let pickedImageResult = PickedImageResult(fileName: filename, uiImage: image)
self.pickedImageResult = pickedImageResult
}
}

self.isPresented = false
}

func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
self.isPresented = false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import SwiftUI
import PhotosUI

public extension View {
func imagePicker(
isShow: Binding<Bool>,
pickedImageResults: Binding<[PickedImageResult]>,
filter: PHPickerFilter = .images,
limit: Int = 1
) -> some View {
self.fullScreenCover(isPresented: isShow) {
MultipleImagePicker(filter: filter, limit: limit, pickedImageResults: pickedImageResults)
}
}
}

struct MultipleImagePicker: UIViewControllerRepresentable {
let filter: PHPickerFilter
let limit: Int
@Binding var pickedImageResults: [PickedImageResult]

func makeUIViewController(context: Context) -> PHPickerViewController {
var configuration = PHPickerConfiguration(photoLibrary: .shared())
configuration.filter = filter
configuration.selectionLimit = limit
let controller = PHPickerViewController(configuration: configuration)
controller.delegate = context.coordinator
return controller
}

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

func makeCoordinator() -> Coordinator {
Coordinator(self)
}

class Coordinator: PHPickerViewControllerDelegate {
var parent: MultipleImagePicker

init(_ parent: MultipleImagePicker) {
self.parent = parent
}

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
for result in results {
let provider = result.itemProvider
provider.loadFileRepresentation(forTypeIdentifier: "public.item") { [weak self] url, _ in
guard provider.canLoadObject(ofClass: UIImage.self) else { return }
provider.loadObject(ofClass: UIImage.self) { image, _ in
guard let image = image as? UIImage else { return }
DispatchQueue.main.async {
let pickedImageResult = PickedImageResult(
fileName: url?.lastPathComponent ?? "",
uiImage: image
)
self?.parent.pickedImageResults.append(pickedImageResult)
}
}
}
}
picker.dismiss(animated: true)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Foundation
import UIKit

public struct PickedImageResult: Equatable {
public let fileName: String
public let uiImage: UIImage
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import SwiftUI
import PhotosUI

public extension View {
func imagePicker(
isShow: Binding<Bool>,
pickedImageResult: Binding<PickedImageResult?>,
filter: PHPickerFilter = .images
) -> some View {
self.fullScreenCover(isPresented: isShow) {
SingleImagePicker(filter: filter, pickedImageResult: pickedImageResult)
}
}
}

struct SingleImagePicker: UIViewControllerRepresentable {
let filter: PHPickerFilter
@Binding var pickedImageResult: PickedImageResult?

func makeUIViewController(context: Context) -> PHPickerViewController {
var configuration = PHPickerConfiguration(photoLibrary: .shared())
configuration.filter = filter
configuration.selectionLimit = 1
let controller = PHPickerViewController(configuration: configuration)
controller.delegate = context.coordinator
return controller
}

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

func makeCoordinator() -> Coordinator {
Coordinator(self)
}

class Coordinator: PHPickerViewControllerDelegate {
var parent: SingleImagePicker

init(_ parent: SingleImagePicker) {
self.parent = parent
}

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
for result in results {
let provider = result.itemProvider
provider.loadFileRepresentation(forTypeIdentifier: "public.item") { [weak self] url, _ in
guard provider.canLoadObject(ofClass: UIImage.self) else { return }
provider.loadObject(ofClass: UIImage.self) { image, _ in
guard let image = image as? UIImage else { return }
DispatchQueue.main.async {
let pickedImageResult = PickedImageResult(
fileName: url?.lastPathComponent ?? "",
uiImage: image
)
self?.parent.pickedImageResult = pickedImageResult
}
}
}
}
picker.dismiss(animated: true)
}
}
}

0 comments on commit 95130fe

Please sign in to comment.