This commit is contained in:
fmodf 2024-07-03 12:47:59 +02:00
parent 024c9d85c8
commit cdccfb9e3e
2 changed files with 182 additions and 71 deletions

View file

@ -4,54 +4,61 @@ import SwiftUI
import UIKit
class MediaManager: NSObject, ObservableObject {
@Published var photos: [UIImage] = []
// @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()
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
self?.fetchPhotos()
self?.setupCameraFeed()
}
NotificationCenter.default.addObserver(self, selector: #selector(appDidBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
// DispatchQueue.main.async { [weak self] in
// // self?.fetchPhotos()
// }
}
private func fetchPhotos() {
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 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 captureDevice = AVCaptureDevice.default(for: .video) else {
guard let backCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) else {
print("Unable to access the back camera!")
return
}
let deviceInput: AVCaptureDeviceInput
do {
deviceInput = try AVCaptureDeviceInput(device: captureDevice)
} catch {
return
let input = try AVCaptureDeviceInput(device: backCamera)
if captureSession.canAddInput(input) {
captureSession.addInput(input)
}
if captureSession.canAddInput(deviceInput) {
captureSession.addInput(deviceInput)
} catch {
print("Error Unable to initialize back camera: \(error.localizedDescription)")
}
let videoOutput = AVCaptureVideoDataOutput()
@ -66,6 +73,7 @@ class MediaManager: NSObject, ObservableObject {
extension MediaManager: AVCaptureVideoDataOutputSampleBufferDelegate {
func captureOutput(_: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from _: AVCaptureConnection) {
print("Capturing output started")
guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
return
}
@ -78,6 +86,25 @@ extension MediaManager: AVCaptureVideoDataOutputSampleBufferDelegate {
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

@ -1,52 +1,136 @@
import SwiftUI
struct AttachmentMediaPickerView: View {
// @StateObject private var mediaManager = MediaManager()
var hasCam: Bool = false
let elements = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"]
@StateObject private var mediaManager = MediaManager()
var body: some View {
ScrollView {
LazyVGrid(columns: Array(repeating: .init(.flexible()), count: 3)) {
ForEach(0 ..< 10) { index in
if index == 0 {
VStack {
Color.red
.frame(height: 100)
Color.red
.frame(height: 100)
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 {
Color.blue
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)
}
}
}
.padding(.horizontal)
// LazyVGrid(columns: [GridItem(), GridItem(), GridItem()]) {
// if let cameraFeed = mediaManager.cameraFeed {
// Button(action: {
// isPickerPresented = true
// }) {
// Image(uiImage: cameraFeed)
// .resizable()
// .aspectRatio(contentMode: .fill)
// }
// }
//
// ForEach(mediaManager.photos, id: \.self) { photo in
// Button(action: {
// selectedPhoto = photo
// }) {
// Image(uiImage: photo)
// .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)
}
}