ios: update image picker (#495)

* switch to PHPicker for photos. TODO add back camera functionality. [rough]

* add back camera selection option

* remove force unwrap of optional

* response to comments

* rerun tests

* refactor naming
This commit is contained in:
IanRDavies
2022-04-04 19:19:54 +01:00
committed by GitHub
parent 309fdf422f
commit 0ecaa59df6
2 changed files with 87 additions and 30 deletions
+75 -17
View File
@@ -7,44 +7,102 @@
//
import SwiftUI
import PhotosUI
struct ImagePicker: UIViewControllerRepresentable {
@Environment(\.presentationMode) var presentationMode
var source: UIImagePickerController.SourceType
enum ImageSource {
case imageLibrary
case camera
}
struct LibraryImagePicker: UIViewControllerRepresentable {
typealias UIViewControllerType = PHPickerViewController
@Binding var image: UIImage?
@Binding var imageUrl: URL?
class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
let parent: ImagePicker
init(_ parent: ImagePicker) {
var didFinishPicking: (_ didSelectItems: Bool) -> Void
class Coordinator: PHPickerViewControllerDelegate {
let parent: LibraryImagePicker
init(_ parent: LibraryImagePicker) {
self.parent = parent
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
parent.didFinishPicking(!results.isEmpty)
guard !results.isEmpty else {
return
}
if let chosenImageProvider = results.first?.itemProvider {
if chosenImageProvider.canLoadObject(ofClass: UIImage.self) {
chosenImageProvider.loadObject(ofClass: UIImage.self) { [weak self] image, error in
DispatchQueue.main.async {
self?.loadImage(object: image, error: error)
}
}
}
}
}
func loadImage(object: Any?, error: Error? = nil) {
if let error = error {
logger.error("Couldn't load image with error: \(error.localizedDescription)")
}
parent.image = object as? UIImage
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: Context) -> PHPickerViewController {
var config = PHPickerConfiguration()
config.filter = .images
config.selectionLimit = 1
let controller = PHPickerViewController(configuration: config)
controller.delegate = context.coordinator
return controller
}
func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {
}
}
struct CameraImagePicker: UIViewControllerRepresentable {
@Environment(\.presentationMode) var presentationMode
@Binding var image: UIImage?
class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
let parent: CameraImagePicker
init(_ parent: CameraImagePicker) {
self.parent = parent
}
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
if let uiImage = info[.originalImage] as? UIImage {
parent.imageUrl = info[.imageURL] as? URL
parent.image = uiImage
}
parent.presentationMode.wrappedValue.dismiss()
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
func makeUIViewController(context: UIViewControllerRepresentableContext<CameraImagePicker>) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.sourceType = source
picker.sourceType = .camera
picker.allowsEditing = false
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<CameraImagePicker>) {
}
}
@@ -14,9 +14,8 @@ struct UserProfile: View {
@State private var editProfile = false
@State private var showChooseSource = false
@State private var showImagePicker = false
@State private var imageSource: UIImagePickerController.SourceType = .photoLibrary
@State private var pickedImage: UIImage? = nil
@State private var tmpImageUrl: URL? = nil
@State private var imageSource: ImageSource = .imageLibrary
@State private var chosenImage: UIImage? = nil
var body: some View {
let user: User = chatModel.currentUser!
@@ -84,14 +83,21 @@ struct UserProfile: View {
showImagePicker = true
}
Button("Choose from library") {
imageSource = .photoLibrary
imageSource = .imageLibrary
showImagePicker = true
}
}
.sheet(isPresented: $showImagePicker) {
ImagePicker(source: imageSource, image: $pickedImage, imageUrl: $tmpImageUrl)
switch imageSource {
case .imageLibrary:
LibraryImagePicker(image: $chosenImage) {
didSelectItem in showImagePicker = false
}
case .camera:
CameraImagePicker(image: $chosenImage)
}
}
.onChange(of: pickedImage) { image in
.onChange(of: chosenImage) { image in
if let image = image,
let data = resizeToSquare(image, 104).jpegData(compressionQuality: 0.85) {
let imageStr = "data:image/jpg;base64,\(data.base64EncodedString())"
@@ -100,13 +106,6 @@ struct UserProfile: View {
} else {
logger.error("UserProfile: resized image is too big \(imageStr.count)")
}
if let tmpImageUrl = tmpImageUrl {
do {
try FileManager.default.removeItem(at: tmpImageUrl)
} catch {
logger.error("UserProfile: file deletion error \(error.localizedDescription)")
}
}
} else {
profile.image = nil
}