mirror of
https://github.com/dscyrescotti/Memola.git
synced 2026-04-19 15:21:29 +02:00
feat: add camera view
This commit is contained in:
@@ -84,6 +84,7 @@
|
||||
ECA738FC2BE61C5200A4542E /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA738FB2BE61C5200A4542E /* Persistence.swift */; };
|
||||
ECA739082BE623F300A4542E /* PenDock.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA739072BE623F300A4542E /* PenDock.swift */; };
|
||||
ECBE52962C1D5900006BDB3D /* PhotoPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBE52952C1D5900006BDB3D /* PhotoPreview.swift */; };
|
||||
ECBE52992C1D60E5006BDB3D /* CameraView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBE52982C1D60E5006BDB3D /* CameraView.swift */; };
|
||||
ECD12A862C19EE3900B96E12 /* ElementObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECD12A852C19EE3900B96E12 /* ElementObject.swift */; };
|
||||
ECD12A8A2C19EFB000B96E12 /* Element.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECD12A892C19EFB000B96E12 /* Element.swift */; };
|
||||
ECD12A8C2C1AEAA900B96E12 /* PhotoObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECD12A8B2C1AEAA900B96E12 /* PhotoObject.swift */; };
|
||||
@@ -183,6 +184,7 @@
|
||||
ECA738FB2BE61C5200A4542E /* Persistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = "<group>"; };
|
||||
ECA739072BE623F300A4542E /* PenDock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenDock.swift; sourceTree = "<group>"; };
|
||||
ECBE52952C1D5900006BDB3D /* PhotoPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPreview.swift; sourceTree = "<group>"; };
|
||||
ECBE52982C1D60E5006BDB3D /* CameraView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraView.swift; sourceTree = "<group>"; };
|
||||
ECD12A852C19EE3900B96E12 /* ElementObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementObject.swift; sourceTree = "<group>"; };
|
||||
ECD12A892C19EFB000B96E12 /* Element.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Element.swift; sourceTree = "<group>"; };
|
||||
ECD12A8B2C1AEAA900B96E12 /* PhotoObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoObject.swift; sourceTree = "<group>"; };
|
||||
@@ -232,6 +234,7 @@
|
||||
EC1B783A2BF9C68C005A34E2 /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ECBE52972C1D6087006BDB3D /* CameraView */,
|
||||
ECFC51252BF8885000D0D051 /* ColorPicker */,
|
||||
);
|
||||
path = Views;
|
||||
@@ -676,6 +679,14 @@
|
||||
path = PhotoPreview;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
ECBE52972C1D6087006BDB3D /* CameraView */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ECBE52982C1D60E5006BDB3D /* CameraView.swift */,
|
||||
);
|
||||
path = CameraView;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
ECD12A872C19EF8700B96E12 /* Elements */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -890,6 +901,7 @@
|
||||
EC0D14212BF79C73009BFE5F /* ToolObject.swift in Sources */,
|
||||
EC50500D2BF6674400B4D86E /* OnDragViewModifier.swift in Sources */,
|
||||
EC9AB09F2C1401A40076AF58 /* EraserObject.swift in Sources */,
|
||||
ECBE52992C1D60E5006BDB3D /* CameraView.swift in Sources */,
|
||||
ECA7389E2BE601CB00A4542E /* QuadVertex.swift in Sources */,
|
||||
ECA738B32BE60D9E00A4542E /* CanvasView.swift in Sources */,
|
||||
ECA738C42BE60E8800A4542E /* MarkerPenStyle.swift in Sources */,
|
||||
|
||||
44
Memola/Components/Views/CameraView/CameraView.swift
Normal file
44
Memola/Components/Views/CameraView/CameraView.swift
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// CameraView.swift
|
||||
// Memola
|
||||
//
|
||||
// Created by Dscyre Scotti on 6/15/24.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct CameraView: UIViewControllerRepresentable {
|
||||
@Binding var image: UIImage?
|
||||
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
|
||||
func makeUIViewController(context: Context) -> UIImagePickerController {
|
||||
let picker = UIImagePickerController()
|
||||
picker.sourceType = .camera
|
||||
picker.delegate = context.coordinator
|
||||
return picker
|
||||
}
|
||||
|
||||
func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) { }
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
Coordinator(self)
|
||||
}
|
||||
|
||||
class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
|
||||
let parent: CameraView
|
||||
|
||||
init(_ parent: CameraView) {
|
||||
self.parent = parent
|
||||
}
|
||||
|
||||
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
|
||||
parent.image = info[.originalImage] as? UIImage
|
||||
parent.dismiss()
|
||||
}
|
||||
|
||||
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
|
||||
parent.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Memola requires access to the camera to capture photos.</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import SwiftUI
|
||||
import PhotosUI
|
||||
import Foundation
|
||||
import AVFoundation
|
||||
|
||||
struct Toolbar: View {
|
||||
@Environment(\.dismiss) var dismiss
|
||||
@@ -19,6 +20,8 @@ struct Toolbar: View {
|
||||
@State var title: String
|
||||
@State var memo: MemoObject
|
||||
@State var photoItem: PhotosPickerItem?
|
||||
@State var opensCamera: Bool = false
|
||||
@State var isCameraAccessDenied: Bool = false
|
||||
|
||||
@FocusState var textFieldState: Bool
|
||||
|
||||
@@ -66,6 +69,22 @@ struct Toolbar: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.fullScreenCover(isPresented: $opensCamera) {
|
||||
CameraView(image: $tool.selectedImage)
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
.alert("Camera Access Denied", isPresented: $isCameraAccessDenied) {
|
||||
Button {
|
||||
if let url = URL(string: UIApplication.openSettingsURLString + "&path=CAMERA/\(String(describing: Bundle.main.bundleIdentifier))") {
|
||||
UIApplication.shared.open(url)
|
||||
}
|
||||
} label: {
|
||||
Text("Open Settings")
|
||||
}
|
||||
Button("Cancel", role: .cancel) { }
|
||||
} message: {
|
||||
Text("Memola requires access to the camera to capture photos. Please open Settings and enable camera access.")
|
||||
}
|
||||
}
|
||||
|
||||
var closeButton: some View {
|
||||
@@ -114,6 +133,7 @@ struct Toolbar: View {
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: "pencil")
|
||||
.fontWeight(.heavy)
|
||||
.contentShape(.circle)
|
||||
.frame(width: size, height: size)
|
||||
.background(tool.selection == .pen ? Color.accentColor : Color.clear)
|
||||
@@ -138,7 +158,7 @@ struct Toolbar: View {
|
||||
if tool.selection == .photo {
|
||||
HStack(spacing: 0) {
|
||||
Button {
|
||||
|
||||
openCamera()
|
||||
} label: {
|
||||
Image(systemName: "camera.fill")
|
||||
.contentShape(.circle)
|
||||
@@ -175,7 +195,6 @@ struct Toolbar: View {
|
||||
history.historyPublisher.send(.undo)
|
||||
} label: {
|
||||
Image(systemName: "arrow.uturn.backward.circle")
|
||||
|
||||
.contentShape(.circle)
|
||||
}
|
||||
.hoverEffect(.lift)
|
||||
@@ -220,6 +239,26 @@ struct Toolbar: View {
|
||||
.hoverEffect(.lift)
|
||||
}
|
||||
|
||||
func openCamera() {
|
||||
let status = AVCaptureDevice.authorizationStatus(for: .video)
|
||||
switch status {
|
||||
case .notDetermined:
|
||||
AVCaptureDevice.requestAccess(for: .video) { status in
|
||||
withAnimation {
|
||||
if status {
|
||||
opensCamera = true
|
||||
} else {
|
||||
isCameraAccessDenied = true
|
||||
}
|
||||
}
|
||||
}
|
||||
case .authorized:
|
||||
opensCamera = true
|
||||
default:
|
||||
isCameraAccessDenied = true
|
||||
}
|
||||
}
|
||||
|
||||
func closeMemo() {
|
||||
withAnimation {
|
||||
canvas.state = .closing
|
||||
|
||||
Reference in New Issue
Block a user