This commit is contained in:
fmodf 2024-07-03 15:47:25 +02:00
parent ce85b7dff9
commit f60c14cc74
3 changed files with 95 additions and 276 deletions

View file

@ -1,110 +0,0 @@
// import AVFoundation
// import Photos
// import SwiftUI
// import UIKit
//
// class MediaManager: NSObject, ObservableObject {
// // @Published var photos: [UIImage] = []
// @Published var cameraFeed: UIImage?
//
// // @Published var galleryAccessLevel: PHAuthorizationStatus = .notDetermined
// @Published var cameraAccessLevel: AVAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: .video)
//
// override init() {
// super.init()
// NotificationCenter.default.addObserver(self, selector: #selector(appDidBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
//
// // DispatchQueue.main.async { [weak self] in
// // // self?.fetchPhotos()
// // }
// }
//
// // private func fetchPhotos() {
// // galleryAccessLevel = PHPhotoLibrary.authorizationStatus()
// //
// // let fetchOptions = PHFetchOptions()
// // fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
// // let assets = PHAsset.fetchAssets(with: .image, options: fetchOptions)
// //
// // let manager = PHImageManager.default()
// // let option = PHImageRequestOptions()
// // option.isSynchronous = true
// //
// // assets.enumerateObjects { asset, _, _ in
// // manager.requestImage(for: asset, targetSize: CGSize(width: 200, height: 200), contentMode: .aspectFill, options: option) { image, _ in
// // if let image = image {
// // DispatchQueue.main.async {
// // self.photos.append(image)
// // }
// // }
// // }
// // }
// // }
//
// private func setupCameraFeed() {
// cameraAccessLevel = AVCaptureDevice.authorizationStatus(for: .video)
//
// let captureSession = AVCaptureSession()
// captureSession.sessionPreset = .medium
//
// guard let backCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) else {
// print("Unable to access the back camera!")
// return
// }
//
// do {
// let input = try AVCaptureDeviceInput(device: backCamera)
// if captureSession.canAddInput(input) {
// captureSession.addInput(input)
// }
// } catch {
// print("Error Unable to initialize back camera: \(error.localizedDescription)")
// }
//
// let videoOutput = AVCaptureVideoDataOutput()
// videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoQueue"))
// if captureSession.canAddOutput(videoOutput) {
// captureSession.addOutput(videoOutput)
// }
//
// captureSession.startRunning()
// }
// }
//
// extension MediaManager: AVCaptureVideoDataOutputSampleBufferDelegate {
// func captureOutput(_: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from _: AVCaptureConnection) {
// print("Capturing output started")
// guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
// return
// }
//
// let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
// let context = CIContext()
// guard let cgImage = context.createCGImage(ciImage, from: ciImage.extent) else {
// return
// }
//
// DispatchQueue.main.async {
// self.cameraFeed = UIImage(cgImage: cgImage)
// print("Updated camera feed")
// }
// }
// }
//
// extension MediaManager {
// func openAppSettings() {
// if
// let appSettingsUrl = URL(string: UIApplication.openSettingsURLString),
// UIApplication.shared.canOpenURL(appSettingsUrl)
// {
// UIApplication.shared.open(appSettingsUrl, completionHandler: nil)
// }
// }
//
// @objc private func appDidBecomeActive() {
// // Update access levels
// // galleryAccessLevel = PHPhotoLibrary.authorizationStatus()
// cameraAccessLevel = AVCaptureDevice.authorizationStatus(for: .video)
// setupCameraFeed()
// }
// }

View file

@ -4,9 +4,9 @@ import SwiftUI
struct AttachmentMediaPickerView: View { struct AttachmentMediaPickerView: View {
@State private var isCameraAccessGranted = AVCaptureDevice.authorizationStatus(for: .video) == .authorized @State private var isCameraAccessGranted = AVCaptureDevice.authorizationStatus(for: .video) == .authorized
@State private var isGalleryAccessGranted = PHPhotoLibrary.authorizationStatus() == .authorized @State private var isGalleryAccessGranted = PHPhotoLibrary.authorizationStatus() == .authorized
@State private var images = [UIImage]()
@State private var photos = [PhotoView]()
let gridSize = UIScreen.main.bounds.width / 3 let gridSize = UIScreen.main.bounds.width / 3
@ -55,12 +55,8 @@ struct AttachmentMediaPickerView: View {
// For pictures // For pictures
if isGalleryAccessGranted { if isGalleryAccessGranted {
ForEach(images.indices, id: \.self) { index in ForEach(photos) { photo in
Image(uiImage: images[index]) photo
.resizable()
.aspectRatio(1, contentMode: .fit)
.frame(maxWidth: .infinity)
.clipped()
} }
} else { } else {
Button { Button {
@ -86,10 +82,12 @@ struct AttachmentMediaPickerView: View {
} }
} }
.onAppear { .onAppear {
DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 0.2) {
checkCameraAccess() checkCameraAccess()
checkGalleryAccess() checkGalleryAccess()
} }
} }
}
private func checkCameraAccess() { private func checkCameraAccess() {
let status = AVCaptureDevice.authorizationStatus(for: .video) let status = AVCaptureDevice.authorizationStatus(for: .video)
@ -153,13 +151,13 @@ struct AttachmentMediaPickerView: View {
contentMode: .aspectFill, contentMode: .aspectFill,
options: option options: option
) { image, _ in ) { image, _ in
if let image = image { image?.scaleAndCropImage(toExampleSize: CGSize(width: gridSize, height: gridSize), completion: { image in
if let image {
DispatchQueue.main.async { DispatchQueue.main.async {
if let img = scaleAndCropImage(image, toSize: CGSize(width: gridSize, height: gridSize)) { self.photos.append(PhotoView(image: image, gridSize: gridSize))
self.images.append(img)
}
} }
} }
})
} }
} }
} }
@ -172,17 +170,45 @@ struct AttachmentMediaPickerView: View {
UIApplication.shared.open(appSettingsUrl, completionHandler: nil) UIApplication.shared.open(appSettingsUrl, completionHandler: nil)
} }
} }
}
func scaleAndCropImage(_ image: UIImage, toSize size: CGSize) -> UIImage? { private struct PhotoView: Identifiable, View {
let imageView = UIImageView(frame: CGRect(origin: .zero, size: size)) let id = UUID()
imageView.contentMode = .scaleAspectFill let gridSize: CGFloat
imageView.image = image
UIGraphicsBeginImageContextWithOptions(size, false, 0.0) @State private var image: UIImage
guard let context = UIGraphicsGetCurrentContext() else { return nil } @State private var ready = false
imageView.layer.render(in: context)
let result = UIGraphicsGetImageFromCurrentImageContext() init(image: UIImage, gridSize: CGFloat) {
UIGraphicsEndImageContext() self.image = image
return result self.gridSize = gridSize
}
var body: some View {
if ready {
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: gridSize, height: gridSize)
.clipped()
} else {
ZStack {
Rectangle()
.fill(Color.Main.backgroundLight)
.overlay {
ProgressView()
}
.frame(width: gridSize, height: gridSize)
}
.onAppear {
image.scaleAndCropImage(toExampleSize: CGSize(width: gridSize, height: gridSize), completion: { image in
if let image {
self.image = image
ready = true
}
})
}
}
} }
} }
@ -215,147 +241,6 @@ struct CameraView: UIViewRepresentable {
} }
func updateUIView(_ uiView: CameraUIView, context _: Context) { func updateUIView(_ uiView: CameraUIView, context _: Context) {
// Update the previewLayer frame when the view updates
uiView.previewLayer?.frame = uiView.bounds uiView.previewLayer?.frame = uiView.bounds
} }
} }
// struct AttachmentMediaPickerView: View {
// @StateObject private var mediaManager = MediaManager()
//
// var body: some View {
// ScrollView {
// LazyVGrid(columns: Array(repeating: .init(.flexible()), count: 3)) {
// ForEach(elements) { element in
// element
// }
// }
// .padding(.horizontal, 8)
// }
// .padding(.vertical, 8)
// }
//
// private var elements: [GridElement] {
// print("Creating elements")
// var result: [GridElement] = []
//
// // camera
// if let feed = mediaManager.cameraFeed, mediaManager.cameraAccessLevel == .authorized {
// result.append(GridElement(id: UUID(), type: .cameraFeed, content: feed) {
// print("Go to capture???")
// })
// print("Added camera feed")
// } else if mediaManager.cameraAccessLevel == .restricted {
// result.append(GridElement(id: UUID(), type: .cameraRestricted, content: nil) {
// print("Show alert")
// })
// print("Added camera restricted")
// } else {
// result.append(GridElement(id: UUID(), type: .cameraAskButton, content: nil) {
// mediaManager.openAppSettings()
// })
// print("Added camera ask button")
// }
//
// // photos
// // if mediaManager.galleryAccessLevel == .restricted {
// // result.append(GridElement(id: UUID(), type: .photoRestricted, content: nil))
// // } else {
// // for photo in mediaManager.photos {
// // result.append(GridElement(id: UUID(), type: .photo, content: photo))
// // }
// // if mediaManager.galleryAccessLevel != .authorized {
// // result.append(GridElement(id: UUID(), type: .photoAskButton, content: nil))
// // }
// // }
//
// return result
// }
// }
//
// private enum GridElementType {
// case cameraFeed
// case cameraAskButton
// case cameraRestricted
// case photo
// case photoAskButton
// case photoRestricted
// }
//
// private struct GridElement: View, Identifiable {
// let id: UUID
// let type: GridElementType
// let content: UIImage?
// let action: () -> Void
//
// var body: some View {
// switch type {
// case .cameraFeed:
// image
// .resizable()
// .aspectRatio(contentMode: .fill)
// .frame(width: 100, height: 100)
// .clipped()
//
// case .cameraAskButton:
// Button {
// action()
// } label: {
// RoundedRectangle(cornerRadius: 5)
// .stroke(Color.Main.backgroundDark, lineWidth: 2)
// .overlay {
// Image(systemName: "camera")
// .foregroundColor(.Material.tortoiseLight300)
// .font(.system(size: 40))
// }
// .frame(height: 100)
// // .resizable()
// // .aspectRatio(contentMode: .fill)
// // .frame(width: 100, height: 100)
// // .clipped()
// }
//
// case .photo:
// image
// .resizable()
// .aspectRatio(contentMode: .fill)
// .frame(width: 100, height: 100)
// .clipped()
//
// case .photoAskButton:
// Button {
// action()
// } label: {
// Image(systemName: "photo.badge.plus")
// .resizable()
// .aspectRatio(contentMode: .fill)
// .frame(width: 100, height: 100)
// .clipped()
// }
//
// case .photoRestricted, .cameraRestricted:
// Button {
// action()
// } label: {
// Image(systemName: "cross")
// .resizable()
// .aspectRatio(contentMode: .fill)
// .frame(width: 100, height: 100)
// .clipped()
// }
// }
// }
//
// private var image: Image {
// guard let content = content else {
// return Image(systemName: "questionmark.square.dashed")
// }
// return Image(uiImage: content)
// }
// }
//
// struct AttachmentMediaPickerView_Previews: PreviewProvider {
// static var previews: some View {
// AttachmentMediaPickerView()
// }
// }

View file

@ -0,0 +1,44 @@
import UIKit
extension UIImage {
func scaleAndCropImage(toExampleSize _: CGSize, completion: @escaping (UIImage?) -> Void) {
DispatchQueue.global(qos: .background).async {
guard let cgImage = self.cgImage else {
DispatchQueue.main.async {
completion(nil)
}
return
}
let contextImage: UIImage = .init(cgImage: cgImage)
var contextSize: CGSize = contextImage.size
var posX: CGFloat = 0.0
var posY: CGFloat = 0.0
let cgwidth: CGFloat = self.size.width
let cgheight: CGFloat = self.size.height
// Check and handle if the image is wider than the requested size
if contextSize.width > contextSize.height {
posX = ((contextSize.width - contextSize.height) / 2)
contextSize.width = contextSize.height
} else if contextSize.width < contextSize.height {
// Check and handle if the image is taller than the requested size
posY = ((contextSize.height - contextSize.width) / 2)
contextSize.height = contextSize.width
}
let rect: CGRect = .init(x: posX, y: posY, width: cgwidth, height: cgheight)
guard let contextCg = contextImage.cgImage, let imgRef = contextCg.cropping(to: rect) else {
DispatchQueue.main.async {
completion(nil)
}
return
}
let image: UIImage = .init(cgImage: imgRef, scale: self.scale, orientation: self.imageOrientation)
DispatchQueue.main.async {
completion(image)
}
}
}
}