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