Camera works, provided you don't go back too rapidly
This commit is contained in:
@@ -26,9 +26,11 @@ final class CameraManager: NSObject, ObservableObject {
|
|||||||
private let continuationQueue = DispatchQueue(label: "com.souschef.continuation")
|
private let continuationQueue = DispatchQueue(label: "com.souschef.continuation")
|
||||||
|
|
||||||
private var isConfigured = false
|
private var isConfigured = false
|
||||||
|
private var cachedPreviewLayer: AVCaptureVideoPreviewLayer?
|
||||||
|
|
||||||
nonisolated override init() {
|
nonisolated override init() {
|
||||||
super.init()
|
super.init()
|
||||||
|
print("🎥 CameraManager.init() - Instance created at \(Date())")
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Authorization
|
// MARK: - Authorization
|
||||||
@@ -53,8 +55,12 @@ final class CameraManager: NSObject, ObservableObject {
|
|||||||
// MARK: - Session Setup
|
// MARK: - Session Setup
|
||||||
|
|
||||||
func setupSession() async throws {
|
func setupSession() async throws {
|
||||||
|
print("🎥 CameraManager.setupSession() - STARTED at \(Date())")
|
||||||
// Only configure once
|
// Only configure once
|
||||||
guard !isConfigured else { return }
|
guard !isConfigured else {
|
||||||
|
print("🎥 CameraManager.setupSession() - Already configured, returning")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure authorization is checked first
|
// Ensure authorization is checked first
|
||||||
await checkAuthorization()
|
await checkAuthorization()
|
||||||
@@ -63,19 +69,29 @@ final class CameraManager: NSObject, ObservableObject {
|
|||||||
throw CameraError.notAuthorized
|
throw CameraError.notAuthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print("🎥 CameraManager.setupSession() - Calling beginConfiguration()")
|
||||||
captureSession.beginConfiguration()
|
captureSession.beginConfiguration()
|
||||||
|
|
||||||
// Set session preset
|
// Set session preset
|
||||||
captureSession.sessionPreset = .high
|
captureSession.sessionPreset = .high
|
||||||
|
print("🎥 CameraManager.setupSession() - Set preset to .high")
|
||||||
|
|
||||||
// Add video input
|
// Add video input
|
||||||
|
print("🎥 CameraManager.setupSession() - About to get video device (LINE 72)")
|
||||||
|
|
||||||
|
#if targetEnvironment(simulator)
|
||||||
|
print("🎥 CameraManager.setupSession() - ⚠️ RUNNING ON SIMULATOR - Camera may not work properly")
|
||||||
|
#endif
|
||||||
|
|
||||||
guard let videoDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back),
|
guard let videoDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back),
|
||||||
let videoInput = try? AVCaptureDeviceInput(device: videoDevice),
|
let videoInput = try? AVCaptureDeviceInput(device: videoDevice),
|
||||||
captureSession.canAddInput(videoInput) else {
|
captureSession.canAddInput(videoInput) else {
|
||||||
|
print("🎥 CameraManager.setupSession() - ❌ FAILED to get video device or add input")
|
||||||
captureSession.commitConfiguration()
|
captureSession.commitConfiguration()
|
||||||
throw CameraError.setupFailed
|
throw CameraError.setupFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print("🎥 CameraManager.setupSession() - ✅ Successfully got video device and input")
|
||||||
captureSession.addInput(videoInput)
|
captureSession.addInput(videoInput)
|
||||||
|
|
||||||
// Add video output
|
// Add video output
|
||||||
@@ -96,6 +112,7 @@ final class CameraManager: NSObject, ObservableObject {
|
|||||||
|
|
||||||
captureSession.commitConfiguration()
|
captureSession.commitConfiguration()
|
||||||
isConfigured = true
|
isConfigured = true
|
||||||
|
print("🎥 CameraManager.setupSession() - ✅ COMPLETED successfully at \(Date())")
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Session Control
|
// MARK: - Session Control
|
||||||
@@ -151,9 +168,26 @@ final class CameraManager: NSObject, ObservableObject {
|
|||||||
|
|
||||||
// MARK: - Preview Layer
|
// MARK: - Preview Layer
|
||||||
|
|
||||||
func previewLayer() -> AVCaptureVideoPreviewLayer {
|
func previewLayer() -> AVCaptureVideoPreviewLayer? {
|
||||||
|
print("🎥 CameraManager.previewLayer() - ⚠️ CALLED at \(Date()) - isConfigured: \(isConfigured)")
|
||||||
|
|
||||||
|
// Only create preview layer after session is configured
|
||||||
|
if !isConfigured {
|
||||||
|
print("🎥 CameraManager.previewLayer() - ❌ Session not configured yet, returning nil")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return cached layer if available
|
||||||
|
if let cached = cachedPreviewLayer {
|
||||||
|
print("🎥 CameraManager.previewLayer() - ✅ Returning cached preview layer")
|
||||||
|
return cached
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and cache new preview layer
|
||||||
|
print("🎥 CameraManager.previewLayer() - ✅ Creating new preview layer")
|
||||||
let layer = AVCaptureVideoPreviewLayer(session: captureSession)
|
let layer = AVCaptureVideoPreviewLayer(session: captureSession)
|
||||||
layer.videoGravity = .resizeAspectFill
|
layer.videoGravity = .resizeAspectFill
|
||||||
|
cachedPreviewLayer = layer
|
||||||
return layer
|
return layer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ final class CookingModeViewModel: ObservableObject {
|
|||||||
cameraManager.stopSession()
|
cameraManager.stopSession()
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPreviewLayer() -> AVCaptureVideoPreviewLayer {
|
func getPreviewLayer() -> AVCaptureVideoPreviewLayer? {
|
||||||
cameraManager.previewLayer()
|
cameraManager.previewLayer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ final class ScannerViewModel: ObservableObject {
|
|||||||
|
|
||||||
nonisolated init(visionService: VisionService = ARVisionService(),
|
nonisolated init(visionService: VisionService = ARVisionService(),
|
||||||
cameraManager: CameraManager = CameraManager()) {
|
cameraManager: CameraManager = CameraManager()) {
|
||||||
|
print("📱 ScannerViewModel.init() - Creating ViewModel at \(Date())")
|
||||||
self.visionService = visionService
|
self.visionService = visionService
|
||||||
self.cameraManager = cameraManager
|
self.cameraManager = cameraManager
|
||||||
}
|
}
|
||||||
@@ -32,9 +33,12 @@ final class ScannerViewModel: ObservableObject {
|
|||||||
// MARK: - Camera Management
|
// MARK: - Camera Management
|
||||||
|
|
||||||
func setupCamera() async {
|
func setupCamera() async {
|
||||||
|
print("📱 ScannerViewModel.setupCamera() - STARTED at \(Date())")
|
||||||
do {
|
do {
|
||||||
try await cameraManager.setupSession()
|
try await cameraManager.setupSession()
|
||||||
|
print("📱 ScannerViewModel.setupCamera() - ✅ SUCCESS at \(Date())")
|
||||||
} catch {
|
} catch {
|
||||||
|
print("📱 ScannerViewModel.setupCamera() - ❌ ERROR: \(error)")
|
||||||
self.error = error
|
self.error = error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,8 +51,9 @@ final class ScannerViewModel: ObservableObject {
|
|||||||
cameraManager.stopSession()
|
cameraManager.stopSession()
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPreviewLayer() -> AVCaptureVideoPreviewLayer {
|
func getPreviewLayer() -> AVCaptureVideoPreviewLayer? {
|
||||||
cameraManager.previewLayer()
|
print("📱 ScannerViewModel.getPreviewLayer() - ⚠️ REQUESTING preview layer at \(Date())")
|
||||||
|
return cameraManager.previewLayer()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Scanning
|
// MARK: - Scanning
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ struct CookingModeView: View {
|
|||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.dismiss) private var dismiss
|
||||||
@StateObject private var viewModel: CookingModeViewModel
|
@StateObject private var viewModel: CookingModeViewModel
|
||||||
@State private var showingAllSteps = false
|
@State private var showingAllSteps = false
|
||||||
|
@State private var previewLayer: AVCaptureVideoPreviewLayer?
|
||||||
|
|
||||||
init(recipe: Recipe) {
|
init(recipe: Recipe) {
|
||||||
_viewModel = StateObject(wrappedValue: CookingModeViewModel(recipe: recipe))
|
_viewModel = StateObject(wrappedValue: CookingModeViewModel(recipe: recipe))
|
||||||
@@ -21,8 +22,8 @@ struct CookingModeView: View {
|
|||||||
NavigationStack {
|
NavigationStack {
|
||||||
ZStack {
|
ZStack {
|
||||||
// Camera preview background
|
// Camera preview background
|
||||||
if viewModel.isMonitoring {
|
if viewModel.isMonitoring, let previewLayer = previewLayer {
|
||||||
CameraPreviewView(previewLayer: viewModel.getPreviewLayer())
|
CameraPreviewView(previewLayer: previewLayer)
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
.opacity(0.3)
|
.opacity(0.3)
|
||||||
}
|
}
|
||||||
@@ -69,6 +70,7 @@ struct CookingModeView: View {
|
|||||||
}
|
}
|
||||||
.task {
|
.task {
|
||||||
await viewModel.setupCamera()
|
await viewModel.setupCamera()
|
||||||
|
previewLayer = viewModel.getPreviewLayer()
|
||||||
viewModel.startCamera()
|
viewModel.startCamera()
|
||||||
}
|
}
|
||||||
.onDisappear {
|
.onDisappear {
|
||||||
|
|||||||
@@ -16,9 +16,15 @@ struct ScannerView: View {
|
|||||||
@State private var detectedPlanes = 0
|
@State private var detectedPlanes = 0
|
||||||
@State private var lastRaycastResult = ""
|
@State private var lastRaycastResult = ""
|
||||||
@State private var showARView = false
|
@State private var showARView = false
|
||||||
|
@State private var previewLayer: AVCaptureVideoPreviewLayer?
|
||||||
|
|
||||||
|
init() {
|
||||||
|
print("🔵 ScannerView.init() - View initialized at \(Date())")
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack {
|
print("🔵 ScannerView.body - Body evaluated at \(Date()), showARView: \(showARView)")
|
||||||
|
return NavigationStack {
|
||||||
ZStack {
|
ZStack {
|
||||||
// AR camera preview or regular camera
|
// AR camera preview or regular camera
|
||||||
if showARView {
|
if showARView {
|
||||||
@@ -28,8 +34,17 @@ struct ScannerView: View {
|
|||||||
)
|
)
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
} else {
|
} else {
|
||||||
CameraPreviewView(previewLayer: viewModel.getPreviewLayer())
|
if let previewLayer = previewLayer {
|
||||||
|
CameraPreviewView(previewLayer: previewLayer)
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
} else {
|
||||||
|
Color.black
|
||||||
|
.ignoresSafeArea()
|
||||||
|
.overlay {
|
||||||
|
ProgressView("Initializing camera...")
|
||||||
|
.foregroundStyle(.white)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overlay UI
|
// Overlay UI
|
||||||
@@ -68,12 +83,19 @@ struct ScannerView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.task {
|
.task {
|
||||||
|
print("🔵 ScannerView.task - Task started at \(Date())")
|
||||||
if !showARView {
|
if !showARView {
|
||||||
|
print("🔵 ScannerView.task - Calling setupCamera()")
|
||||||
await viewModel.setupCamera()
|
await viewModel.setupCamera()
|
||||||
|
print("🔵 ScannerView.task - Getting preview layer after setup")
|
||||||
|
previewLayer = viewModel.getPreviewLayer()
|
||||||
|
print("🔵 ScannerView.task - Preview layer set: \(previewLayer != nil)")
|
||||||
|
print("🔵 ScannerView.task - Calling startCamera()")
|
||||||
viewModel.startCamera()
|
viewModel.startCamera()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onDisappear {
|
.onDisappear {
|
||||||
|
print("🔵 ScannerView.onDisappear - Cleaning up at \(Date())")
|
||||||
viewModel.cleanup()
|
viewModel.cleanup()
|
||||||
}
|
}
|
||||||
.alert("Camera Error", isPresented: .constant(viewModel.error != nil)) {
|
.alert("Camera Error", isPresented: .constant(viewModel.error != nil)) {
|
||||||
@@ -174,7 +196,11 @@ struct ScannerView: View {
|
|||||||
withAnimation {
|
withAnimation {
|
||||||
showARView.toggle()
|
showARView.toggle()
|
||||||
if !showARView {
|
if !showARView {
|
||||||
|
Task {
|
||||||
|
await viewModel.setupCamera()
|
||||||
|
previewLayer = viewModel.getPreviewLayer()
|
||||||
viewModel.startCamera()
|
viewModel.startCamera()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
viewModel.stopCamera()
|
viewModel.stopCamera()
|
||||||
}
|
}
|
||||||
@@ -246,10 +272,12 @@ struct CameraPreviewView: UIViewRepresentable {
|
|||||||
let previewLayer: AVCaptureVideoPreviewLayer
|
let previewLayer: AVCaptureVideoPreviewLayer
|
||||||
|
|
||||||
func makeUIView(context: Context) -> UIView {
|
func makeUIView(context: Context) -> UIView {
|
||||||
|
print("🟢 CameraPreviewView.makeUIView() - Creating preview view at \(Date())")
|
||||||
let view = UIView(frame: .zero)
|
let view = UIView(frame: .zero)
|
||||||
view.backgroundColor = .black
|
view.backgroundColor = .black
|
||||||
previewLayer.frame = view.bounds
|
previewLayer.frame = view.bounds
|
||||||
view.layer.addSublayer(previewLayer)
|
view.layer.addSublayer(previewLayer)
|
||||||
|
print("🟢 CameraPreviewView.makeUIView() - Preview layer added to view")
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user