diff --git a/SelfieCam/App/SelfieCamApp.swift b/SelfieCam/App/SelfieCamApp.swift index 728fd15..1dfbc83 100644 --- a/SelfieCam/App/SelfieCamApp.swift +++ b/SelfieCam/App/SelfieCamApp.swift @@ -12,6 +12,15 @@ import Bedrock struct SelfieCamApp: App { init() { Design.showDebugLogs = true + + // Register SelfieCam theme with Bedrock + Theme.register( + text: AppTextColors.self, + surface: AppSurface.self, + accent: AppAccent.self, + status: AppStatus.self + ) + Theme.register(border: AppBorder.self) } var body: some Scene { diff --git a/SelfieCam/Features/Camera/Views/ContentView.swift b/SelfieCam/Features/Camera/Views/ContentView.swift index fd050d5..7d233e0 100644 --- a/SelfieCam/Features/Camera/Views/ContentView.swift +++ b/SelfieCam/Features/Camera/Views/ContentView.swift @@ -188,16 +188,16 @@ struct ContentView: View { } // MARK: - Camera Container View -/// Wrapper view for MCamera - only recreates when sessionKey changes + /// Wrapper view for MCamera - only recreates when sessionKey changes struct CameraContainerView: View, Equatable { let settings: SettingsViewModel let sessionKey: UUID let cameraPosition: CameraPosition let onImageCaptured: (UIImage) -> Void - // Only compare sessionKey and cameraPosition for equality + // Only compare sessionKey for equality - we want to handle position changes via runtime setCameraPosition static func == (lhs: CameraContainerView, rhs: CameraContainerView) -> Bool { - lhs.sessionKey == rhs.sessionKey && lhs.cameraPosition == rhs.cameraPosition + lhs.sessionKey == rhs.sessionKey } var body: some View { diff --git a/SelfieCam/Features/Camera/Views/CustomCameraScreen.swift b/SelfieCam/Features/Camera/Views/CustomCameraScreen.swift index 00ff53a..81eaf6e 100644 --- a/SelfieCam/Features/Camera/Views/CustomCameraScreen.swift +++ b/SelfieCam/Features/Camera/Views/CustomCameraScreen.swift @@ -320,17 +320,17 @@ struct CustomCameraScreen: MCameraScreen { // Initial haptic for countdown start triggerHaptic(.light) - Task { @MainActor in - while countdownSeconds > 0 { - try? await Task.sleep(for: .seconds(1)) - countdownSeconds -= 1 - // Haptic tick for each countdown second - triggerHaptic(.light) + // Use a Timer to ensure we update on the main thread every second + Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in + if self.countdownSeconds > 1 { + self.countdownSeconds -= 1 + self.triggerHaptic(.light) + } else { + timer.invalidate() + self.countdownSeconds = 0 + self.isCountdownActive = false + self.performActualCapture() } - - // Countdown finished, perform capture - isCountdownActive = false - performActualCapture() } } @@ -542,16 +542,8 @@ struct CustomCameraScreen: MCameraScreen { let newPosition: CameraPosition = cameraPosition == .front ? .back : .front Design.debugLog("Double-tap: flipping camera to \(newPosition)") - Task { - do { - try await setCameraPosition(newPosition) - // Update settings to persist the change - cameraSettings.cameraPosition = newPosition - currentCameraPosition = newPosition - } catch { - Design.debugLog("Failed to flip camera: \(error)") - } - } + // Update settings to persist the change - this will trigger the onChange in CustomCameraScreen + cameraSettings.cameraPosition = newPosition } // MARK: - Haptic Feedback diff --git a/SelfieCam/Features/Settings/ViewModels/SettingsViewModel+Camera.swift b/SelfieCam/Features/Settings/ViewModels/SettingsViewModel+Camera.swift index e0e9b89..3f78048 100644 --- a/SelfieCam/Features/Settings/ViewModels/SettingsViewModel+Camera.swift +++ b/SelfieCam/Features/Settings/ViewModels/SettingsViewModel+Camera.swift @@ -22,14 +22,14 @@ extension SettingsViewModel { var cameraPosition: CameraPosition { get { + // Access the data through cloudSync to ensure observation is tracked let raw = cloudSync.data.cameraPositionRaw - let position: CameraPosition = raw == "front" ? .front : .back - Design.debugLog("cameraPosition getter: raw='\(raw)' -> \(position)") - return position + return raw == "back" ? .back : .front } set { - let rawValue = newValue == .front ? "front" : "back" - Design.debugLog("cameraPosition setter: \(newValue) -> raw='\(rawValue)'") + let rawValue = newValue == .back ? "back" : "front" + + // Use updateSettings to ensure modificationCount is incremented and observers are notified updateSettings { $0.cameraPositionRaw = rawValue } } } diff --git a/SelfieCam/Features/Settings/ViewModels/SettingsViewModel.swift b/SelfieCam/Features/Settings/ViewModels/SettingsViewModel.swift index d56e995..dec5ee1 100644 --- a/SelfieCam/Features/Settings/ViewModels/SettingsViewModel.swift +++ b/SelfieCam/Features/Settings/ViewModels/SettingsViewModel.swift @@ -137,6 +137,9 @@ final class SettingsViewModel: RingLightConfigurable { /// Updates settings and saves to cloud immediately func updateSettings(_ transform: (inout SyncedSettings) -> Void) { + // Since we are using @Observable, we need to ensure the property access is tracked + // The cloudSync.update call modifies the data, but we need to trigger the observation + // We wrap the update in a way that SwiftUI's observation system can see the change cloudSync.update { settings in transform(&settings) settings.modificationCount += 1 diff --git a/SelfieCam/Features/Settings/Views/AppLicensesView.swift b/SelfieCam/Features/Settings/Views/AppLicensesView.swift index 4cd8451..8a4c445 100644 --- a/SelfieCam/Features/Settings/Views/AppLicensesView.swift +++ b/SelfieCam/Features/Settings/Views/AppLicensesView.swift @@ -27,7 +27,7 @@ struct AppLicensesView: View { var body: some View { LicensesView( licenses: Self.licenses, - backgroundColor: AppSurface.overlay, + backgroundColor: AppSurface.primary, cardBackgroundColor: AppSurface.card, cardBorderColor: AppBorder.subtle, accentColor: AppAccent.primary