From 9f6523a6bd4ff48ddeb9b96fe582fd4d13489453 Mon Sep 17 00:00:00 2001 From: Pablo Date: Mon, 23 Dec 2024 18:21:48 -0400 Subject: [PATCH 1/2] Make use of PhotosPicker (aka CameraRoll). --- SwiftUI-AI-Wrapper.xcodeproj/project.pbxproj | 6 -- SwiftUI-AI-Wrapper/CameraView.swift | 39 ++++++- SwiftUI-AI-Wrapper/PhotoPicker.swift | 103 ------------------- 3 files changed, 34 insertions(+), 114 deletions(-) delete mode 100644 SwiftUI-AI-Wrapper/PhotoPicker.swift diff --git a/SwiftUI-AI-Wrapper.xcodeproj/project.pbxproj b/SwiftUI-AI-Wrapper.xcodeproj/project.pbxproj index 2ec07da..c2e60d5 100644 --- a/SwiftUI-AI-Wrapper.xcodeproj/project.pbxproj +++ b/SwiftUI-AI-Wrapper.xcodeproj/project.pbxproj @@ -23,7 +23,6 @@ 318DAF612C3BA56A00619995 /* InputMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 318DAF602C3BA56A00619995 /* InputMessageView.swift */; }; 318DAF632C3BA5C600619995 /* ConnectionRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 318DAF622C3BA5C600619995 /* ConnectionRequest.swift */; }; 318DAF652C3BA5FA00619995 /* DateExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 318DAF642C3BA5FA00619995 /* DateExtensions.swift */; }; - 318DAF672C3BA62900619995 /* PhotoPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 318DAF662C3BA62900619995 /* PhotoPicker.swift */; }; 318DAF6B2C3CDE0100619995 /* StringHash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 318DAF6A2C3CDE0100619995 /* StringHash.swift */; }; /* End PBXBuildFile section */ @@ -45,7 +44,6 @@ 318DAF602C3BA56A00619995 /* InputMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputMessageView.swift; sourceTree = ""; }; 318DAF622C3BA5C600619995 /* ConnectionRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionRequest.swift; sourceTree = ""; }; 318DAF642C3BA5FA00619995 /* DateExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateExtensions.swift; sourceTree = ""; }; - 318DAF662C3BA62900619995 /* PhotoPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPicker.swift; sourceTree = ""; }; 318DAF6A2C3CDE0100619995 /* StringHash.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringHash.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -83,7 +81,6 @@ 318DAF3E2C3BA1E900619995 /* ContentView.swift */, 318DAF502C3BA2DE00619995 /* HistoryView.swift */, 318DAF4A2C3BA22400619995 /* CameraView.swift */, - 318DAF662C3BA62900619995 /* PhotoPicker.swift */, 318DAF5C2C3BA42800619995 /* PhotoView.swift */, 318DAF522C3BA2EF00619995 /* Models */, 318DAF682C3BADFE00619995 /* ChatViews */, @@ -212,7 +209,6 @@ 318DAF6B2C3CDE0100619995 /* StringHash.swift in Sources */, 318DAF612C3BA56A00619995 /* InputMessageView.swift in Sources */, 318DAF652C3BA5FA00619995 /* DateExtensions.swift in Sources */, - 318DAF672C3BA62900619995 /* PhotoPicker.swift in Sources */, 318DAF3F2C3BA1E900619995 /* ContentView.swift in Sources */, 318DAF5D2C3BA42800619995 /* PhotoView.swift in Sources */, 318DAF3D2C3BA1E900619995 /* SwiftUI_AI_WrapperApp.swift in Sources */, @@ -356,7 +352,6 @@ ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSCameraUsageDescription = "Access to your camera is required to take photos of objects"; - INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Permission required to upload photos to the AI Wrapper"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -387,7 +382,6 @@ ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSCameraUsageDescription = "Access to your camera is required to take photos of objects"; - INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Permission required to upload photos to the AI Wrapper"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; diff --git a/SwiftUI-AI-Wrapper/CameraView.swift b/SwiftUI-AI-Wrapper/CameraView.swift index 4ba934e..612b26a 100644 --- a/SwiftUI-AI-Wrapper/CameraView.swift +++ b/SwiftUI-AI-Wrapper/CameraView.swift @@ -8,6 +8,7 @@ import SwiftUI import AVFoundation +import PhotosUI struct CameraView: View { @@ -32,6 +33,7 @@ struct CameraView: View { //@State private var imagePickerOpacity: CGFloat = 0 @State private var selectedImage: UIImage? = nil @State private var filename: String? = nil + @State private var selectedItem: PhotosPickerItem? @Binding var showHistory: Bool @@ -158,10 +160,7 @@ struct CameraView: View { .padding(25) } .foregroundColor(.white) - .sheet(isPresented: $showImagePicker) { - PhotoPicker(isPresented: $showImagePicker, selectedImage: $selectedImage, filename: $filename) - .accentColor(.blue) - } + .photosPicker(isPresented: $showImagePicker, selection: $selectedItem, matching: .images) Spacer() Button(action: { @@ -250,6 +249,11 @@ struct CameraView: View { } } } + .onChange(of: selectedItem) { newItem in + if let item = newItem { + handleSelection(item: item) + } + } .edgesIgnoringSafeArea(.all) } @@ -316,7 +320,32 @@ struct CameraView: View { } } - + // Handles the selected photo, extracting the image and filename. + private func handleSelection(item: PhotosPickerItem) { + // Load the image as a UIImage + item.loadTransferable(type: Data.self) { result in + DispatchQueue.main.async { + switch result { + case .success(let data): + if let data = data, let image = UIImage(data: data) { + self.selectedImage = image + } + case .failure(let error): + self.selectedItem = nil + print("Error loading image: \(error.localizedDescription)") + } + } + } + + // Retrieve the filename (if available) + if let assetIdentifier = item.itemIdentifier { + let asset = PHAsset.fetchAssets(withLocalIdentifiers: [assetIdentifier], options: nil).firstObject + filename = asset?.value(forKey: "filename") as? String + } + + // Clear CameraRoll item selection + selectedItem = nil + } } diff --git a/SwiftUI-AI-Wrapper/PhotoPicker.swift b/SwiftUI-AI-Wrapper/PhotoPicker.swift deleted file mode 100644 index 613dbb4..0000000 --- a/SwiftUI-AI-Wrapper/PhotoPicker.swift +++ /dev/null @@ -1,103 +0,0 @@ -// AI Wrapper SwiftUI -// Created by Adam Lyttle on 7/9/2024 - -// Make cool stuff and share your build with me: - -// --> x.com/adamlyttleapps -// --> github.com/adamlyttleapps - -import SwiftUI -import PhotosUI - -struct PhotoPicker: UIViewControllerRepresentable { - @Binding var isPresented: Bool - @Binding var selectedImage: UIImage? - @Binding var filename: String? - - func makeCoordinator() -> Coordinator { - return Coordinator(self) - } - - func makeUIViewController(context: Context) -> PHPickerViewController { - var config = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())//PHPickerConfiguration() - config.filter = .images - config.selectionLimit = 1 - let picker = PHPickerViewController(configuration: config) - picker.delegate = context.coordinator - return picker - } - - func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) { - } - - class Coordinator: NSObject, PHPickerViewControllerDelegate { - let parent: PhotoPicker - - init(_ parent: PhotoPicker) { - self.parent = parent - } - - - - func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { - parent.isPresented = false - - if let result = results.first { - let assetID = result.assetIdentifier - let options = PHImageRequestOptions() - options.isSynchronous = false - options.deliveryMode = .highQualityFormat - options.isNetworkAccessAllowed = true - - if let assetID = assetID { - PHPhotoLibrary.requestAuthorization { status in - if status == .authorized { - let asset = PHAsset.fetchAssets(withLocalIdentifiers: [assetID], options: nil).firstObject - PHImageManager.default().requestImageDataAndOrientation(for: asset!, options: options) { imageData, dataUTI, orientation, info in - if let imageData = imageData { - DispatchQueue.main.async { - self.parent.selectedImage = UIImage(data: imageData) - // Get metadata - if let imageSource = CGImageSourceCreateWithData(imageData as CFData, nil), - let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [CFString: Any] { - // Get the original file format - let fileFormat = imageProperties[kCGImageSourceTypeIdentifierHint] - print("File format: \(fileFormat ?? "Unknown")") - - // Get the resolution - let width = imageProperties[kCGImagePropertyPixelWidth] ?? "Unknown" - let height = imageProperties[kCGImagePropertyPixelHeight] ?? "Unknown" - print("Resolution: \(width) x \(height)") - - // Get the file size - let fileSize = imageProperties[kCGImagePropertyFileSize] ?? "Unknown" - print("File size: \(fileSize) bytes") - - - // Get the filename - let resources = PHAssetResource.assetResources(for: asset!) - if let resource = resources.first { - let filename = resource.originalFilename - print("Filename: \(filename)") - DispatchQueue.main.async { - self.parent.filename = filename - } - } - - } - } - } - } - } else { - print("Authorization not granted") - } - } - } - } - } - - - - - } -} From fc492a5c70963b6dd3758e86fe6865083e410d6b Mon Sep 17 00:00:00 2001 From: Pablo Paciello Date: Sat, 22 Feb 2025 19:43:20 +0100 Subject: [PATCH 2/2] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 07bbb47..5ef3ae5 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,6 @@ private let sharedSecretKey = "secret_key" 3. **Configure Privacy Settings**: If you are adding this wrapper to an existing project, ensure that you add the following keys to your Info.plist: ``` -Privacy - Photo Library Usage Description Privacy - Camera Usage Description ```