From 0b609bfe9315cf0d459da62c3cfff1e9e2319947 Mon Sep 17 00:00:00 2001 From: fmodf Date: Sat, 17 Aug 2024 12:39:40 +0200 Subject: [PATCH] wip --- .../AppData/Store/ConversationStore.swift | 24 +++- .../MediaPicker/CameraCellPreview.swift | 66 +++++++++ .../MediaPicker/CameraPicker.swift | 50 +++++++ .../Attachments/MediaPicker/CameraView.swift | 36 +++++ .../MediaPicker/MediaPickerView.swift | 133 +----------------- project.yml | 10 -- 6 files changed, 177 insertions(+), 142 deletions(-) create mode 100644 ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraCellPreview.swift create mode 100644 ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraPicker.swift create mode 100644 ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraView.swift diff --git a/ConversationsClassic/AppData/Store/ConversationStore.swift b/ConversationsClassic/AppData/Store/ConversationStore.swift index 817f7aa..e31a841 100644 --- a/ConversationsClassic/AppData/Store/ConversationStore.swift +++ b/ConversationsClassic/AppData/Store/ConversationStore.swift @@ -1,4 +1,3 @@ -import Collections import Combine import Foundation import GRDB @@ -68,3 +67,26 @@ private extension ConversationStore { } } } + +// var isAuthorized: Bool { +// get async { +// let status = AVCaptureDevice.authorizationStatus(for: .video) +// +// // Determine if the user previously authorized camera access. +// var isAuthorized = status == .authorized +// +// // If the system hasn't determined the user's authorization status, +// // explicitly prompt them for approval. +// if status == .notDetermined { +// isAuthorized = await AVCaptureDevice.requestAccess(for: .video) +// } +// +// return isAuthorized +// } +// } +// +// +// func setUpCaptureSession() async { +// guard await isAuthorized else { return } +// // Set up the capture session. +// } diff --git a/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraCellPreview.swift b/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraCellPreview.swift new file mode 100644 index 0000000..b74c01b --- /dev/null +++ b/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraCellPreview.swift @@ -0,0 +1,66 @@ +import AVFoundation +import SwiftUI + +struct CameraCellPreview: View { + @Environment(\.router) var router + @State private var cameraAuthorized = false + + var body: some View { + Group { + if cameraAuthorized { + ZStack { + CameraView() + .aspectRatio(1, contentMode: .fit) + .frame(maxWidth: .infinity) + Image(systemName: "camera") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 40, height: 40) + .foregroundColor(.white) + .padding(8) + .background(Color.black.opacity(0.5)) + .clipShape(Circle()) + .padding(8) + } + .onTapGesture { + router.showScreen(.fullScreenCover) { _ in + CameraPicker() + .ignoresSafeArea(.all) + } + } + } else { + Button { + openAppSettings() + } label: { + ZStack { + Rectangle() + .fill(Color.Material.Background.light) + .overlay { + VStack { + Image(systemName: "camera") + .foregroundColor(.Material.Elements.active) + .font(.system(size: 30)) + Text("Allow camera access") + .foregroundColor(.Material.Text.main) + .font(.body3) + } + } + .frame(height: 100) + } + } + } + } + .task { + await checkAuthorization() + } + } + + private func checkAuthorization() async { + let status = AVCaptureDevice.authorizationStatus(for: .video) + var isAuthorized = status == .authorized + if status == .notDetermined { + isAuthorized = await AVCaptureDevice.requestAccess(for: .video) + } + cameraAuthorized = isAuthorized + } +} diff --git a/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraPicker.swift b/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraPicker.swift new file mode 100644 index 0000000..646a0d4 --- /dev/null +++ b/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraPicker.swift @@ -0,0 +1,50 @@ +import Foundation +import Photos +import SwiftUI + +struct CameraPicker: UIViewControllerRepresentable { + // var sourceType: UIImagePickerController.SourceType + // var completionHandler: (Data, SharingCameraMediaType) -> Void + + func makeUIViewController(context: Context) -> UIImagePickerController { + let picker = UIImagePickerController() + picker.sourceType = .camera + picker.delegate = context.coordinator + picker.mediaTypes = [UTType.movie.identifier, UTType.image.identifier] + picker.videoQuality = .typeHigh + picker.videoMaximumDuration = Const.videoDurationLimit + picker.view.backgroundColor = .clear + return picker + } + + func updateUIViewController(_: UIImagePickerController, context _: Context) {} + + func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate { + let parent: CameraPicker + + init(_ parent: CameraPicker) { + self.parent = parent + } + + func imagePickerController(_: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { + // swiftlint:disable:next force_cast + let mediaType = info[.mediaType] as! String + + // if mediaType == UTType.image.identifier { + // if let image = info[.originalImage] as? UIImage { + // let data = image.jpegData(compressionQuality: 1.0) ?? Data() + // parent.completionHandler(data, .photo) + // } + // } else if mediaType == UTType.movie.identifier { + // if let url = info[.mediaURL] as? URL { + // let data = try? Data(contentsOf: url) + // parent.completionHandler(data ?? Data(), .video) + // } + // } + } + } +} diff --git a/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraView.swift b/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraView.swift new file mode 100644 index 0000000..23e7b55 --- /dev/null +++ b/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraView.swift @@ -0,0 +1,36 @@ +import AVFoundation +import SwiftUI +import UIKit + +class CameraUIView: UIView { + var previewLayer: AVCaptureVideoPreviewLayer? + + override func layoutSubviews() { + super.layoutSubviews() + previewLayer?.frame = bounds + } +} + +struct CameraView: UIViewRepresentable { + func makeUIView(context _: Context) -> CameraUIView { + let view = CameraUIView() + + let captureSession = AVCaptureSession() + guard let captureDevice = AVCaptureDevice.default(for: .video) else { return view } + guard let input = try? AVCaptureDeviceInput(device: captureDevice) else { return view } + captureSession.addInput(input) + + let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) + previewLayer.videoGravity = .resizeAspectFill + view.layer.addSublayer(previewLayer) + view.previewLayer = previewLayer + + captureSession.startRunning() + + return view + } + + func updateUIView(_ uiView: CameraUIView, context _: Context) { + uiView.previewLayer?.frame = uiView.bounds + } +} diff --git a/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/MediaPickerView.swift b/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/MediaPickerView.swift index b265b1d..66accb4 100644 --- a/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/MediaPickerView.swift +++ b/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/MediaPickerView.swift @@ -7,7 +7,7 @@ struct MediaPickerView: View { // @State private var showCameraPicker = false // @State private var cameraReady = false - // @State private var selectedItems: [String] = [] + @State private var selectedItems: [String] = [] var body: some View { let columns = Array(repeating: GridItem(.flexible(), spacing: 0), count: 3) @@ -17,56 +17,7 @@ struct MediaPickerView: View { ScrollView(showsIndicators: false) { LazyVGrid(columns: columns, spacing: 0) { // For camera - // if store.state.sharingState.isCameraAccessGranted { - // if cameraReady { - // ZStack { - // CameraView() - // .aspectRatio(1, contentMode: .fit) - // .frame(maxWidth: .infinity) - // Image(systemName: "camera") - // .resizable() - // .aspectRatio(contentMode: .fit) - // .frame(width: 40, height: 40) - // .foregroundColor(.white) - // .padding(8) - // .background(Color.black.opacity(0.5)) - // .clipShape(Circle()) - // .padding(8) - // } - // .onTapGesture { - // showCameraPicker = true - // } - // } else { - // ProgressView() - // .frame(maxWidth: .infinity) - // .frame(height: 100) - // .onAppear { - // DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { - // cameraReady = true - // } - // } - // } - // } else { - // Button { - // openAppSettings() - // } label: { - // ZStack { - // Rectangle() - // .fill(Color.Material.Background.light) - // .overlay { - // VStack { - // Image(systemName: "camera") - // .foregroundColor(.Material.Elements.active) - // .font(.system(size: 30)) - // Text("Allow camera access") - // .foregroundColor(.Material.Text.main) - // .font(.body3) - // } - // } - // .frame(height: 100) - // } - // } - // } + CameraCellPreview() // For gallery // if store.state.sharingState.isGalleryAccessGranted { @@ -207,83 +158,3 @@ private struct GridViewItem: View { // } } } - -// class CameraUIView: UIView { -// var previewLayer: AVCaptureVideoPreviewLayer? -// -// override func layoutSubviews() { -// super.layoutSubviews() -// previewLayer?.frame = bounds -// } -// } -// -// struct CameraView: UIViewRepresentable { -// func makeUIView(context _: Context) -> CameraUIView { -// let view = CameraUIView() -// -// let captureSession = AVCaptureSession() -// guard let captureDevice = AVCaptureDevice.default(for: .video) else { return view } -// guard let input = try? AVCaptureDeviceInput(device: captureDevice) else { return view } -// captureSession.addInput(input) -// -// let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) -// previewLayer.videoGravity = .resizeAspectFill -// view.layer.addSublayer(previewLayer) -// view.previewLayer = previewLayer -// -// captureSession.startRunning() -// -// return view -// } -// -// func updateUIView(_ uiView: CameraUIView, context _: Context) { -// uiView.previewLayer?.frame = uiView.bounds -// } -// } -// -// struct CameraPicker: UIViewControllerRepresentable { -// var sourceType: UIImagePickerController.SourceType -// var completionHandler: (Data, SharingCameraMediaType) -> Void -// -// func makeUIViewController(context: Context) -> UIImagePickerController { -// let picker = UIImagePickerController() -// picker.sourceType = sourceType -// picker.delegate = context.coordinator -// picker.mediaTypes = [UTType.movie.identifier, UTType.image.identifier] -// picker.videoQuality = .typeHigh -// picker.videoMaximumDuration = Const.videoDurationLimit -// picker.view.backgroundColor = .clear -// return picker -// } -// -// func updateUIViewController(_: UIImagePickerController, context _: Context) {} -// -// func makeCoordinator() -> Coordinator { -// Coordinator(self) -// } -// -// class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate { -// let parent: CameraPicker -// -// init(_ parent: CameraPicker) { -// self.parent = parent -// } -// -// func imagePickerController(_: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { -// // swiftlint:disable:next force_cast -// let mediaType = info[.mediaType] as! String -// -// if mediaType == UTType.image.identifier { -// if let image = info[.originalImage] as? UIImage { -// let data = image.jpegData(compressionQuality: 1.0) ?? Data() -// parent.completionHandler(data, .photo) -// } -// } else if mediaType == UTType.movie.identifier { -// if let url = info[.mediaURL] as? URL { -// let data = try? Data(contentsOf: url) -// parent.completionHandler(data ?? Data(), .video) -// } -// } -// } -// } -// } diff --git a/project.yml b/project.yml index e4f5f68..a07200b 100644 --- a/project.yml +++ b/project.yml @@ -5,12 +5,6 @@ options: postGenCommand: swiftgen packages: - Collections: - url: https://github.com/apple/swift-collections - majorVersion: 1.1.2 - Algorithms: - url: https://github.com/apple/swift-algorithms - majorVersion: 1.2.0 SwiftfulRouting: url: https://github.com/SwiftfulThinking/SwiftfulRouting majorVersion: 5.3.5 @@ -83,10 +77,6 @@ targets: - sdk: Security.framework # - framework: Lib/WebRTC.xcframework # - target: Engine - - package: Collections - link: true - - package: Algorithms - link: true - package: SwiftfulRouting link: true - package: MartinOMEMO