Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
915088f180
commit
eedd709ef5
@ -2,47 +2,7 @@ import SwiftUI
|
|||||||
import MijickCamera
|
import MijickCamera
|
||||||
import Bedrock
|
import Bedrock
|
||||||
|
|
||||||
// MARK: - Camera Settings Observable
|
|
||||||
/// Shared observable class for camera settings to prevent MCamera recreation on changes
|
|
||||||
@Observable @MainActor
|
|
||||||
final class CameraSettingsState {
|
|
||||||
var photoQuality: PhotoQuality
|
|
||||||
var isRingLightEnabled: Bool
|
|
||||||
var ringLightColor: Color
|
|
||||||
var ringLightSize: CGFloat
|
|
||||||
var ringLightOpacity: Double
|
|
||||||
var flashMode: CameraFlashMode
|
|
||||||
var isFlashSyncedWithRingLight: Bool
|
|
||||||
var hdrMode: CameraHDRMode
|
|
||||||
var isGridVisible: Bool
|
|
||||||
var cameraPosition: CameraPosition
|
|
||||||
|
|
||||||
init(settings: SettingsViewModel) {
|
|
||||||
self.photoQuality = settings.photoQuality
|
|
||||||
self.isRingLightEnabled = settings.isRingLightEnabled
|
|
||||||
self.ringLightColor = settings.lightColor
|
|
||||||
self.ringLightSize = settings.ringSize
|
|
||||||
self.ringLightOpacity = settings.ringLightOpacity
|
|
||||||
self.flashMode = settings.flashMode
|
|
||||||
self.isFlashSyncedWithRingLight = settings.isFlashSyncedWithRingLight
|
|
||||||
self.hdrMode = settings.hdrMode
|
|
||||||
self.isGridVisible = settings.isGridVisible
|
|
||||||
self.cameraPosition = settings.cameraPosition
|
|
||||||
}
|
|
||||||
|
|
||||||
func update(from settings: SettingsViewModel) {
|
|
||||||
self.photoQuality = settings.photoQuality
|
|
||||||
self.isRingLightEnabled = settings.isRingLightEnabled
|
|
||||||
self.ringLightColor = settings.lightColor
|
|
||||||
self.ringLightSize = settings.ringSize
|
|
||||||
self.ringLightOpacity = settings.ringLightOpacity
|
|
||||||
self.flashMode = settings.flashMode
|
|
||||||
self.isFlashSyncedWithRingLight = settings.isFlashSyncedWithRingLight
|
|
||||||
self.hdrMode = settings.hdrMode
|
|
||||||
self.isGridVisible = settings.isGridVisible
|
|
||||||
self.cameraPosition = settings.cameraPosition
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ContentView: View {
|
struct ContentView: View {
|
||||||
@State private var settings = SettingsViewModel()
|
@State private var settings = SettingsViewModel()
|
||||||
@ -55,8 +15,7 @@ struct ContentView: View {
|
|||||||
@State private var isSavingPhoto = false
|
@State private var isSavingPhoto = false
|
||||||
@State private var saveError: String?
|
@State private var saveError: String?
|
||||||
|
|
||||||
/// Camera settings in a shared observable to prevent MCamera recreation
|
/// Settings are managed by SettingsViewModel which is already @Observable
|
||||||
@State private var cameraSettings: CameraSettingsState?
|
|
||||||
|
|
||||||
/// Unique key to force MCamera recreation after photo capture
|
/// Unique key to force MCamera recreation after photo capture
|
||||||
/// Incrementing this value creates a new camera session with fresh AVCapturePhotoOutput
|
/// Incrementing this value creates a new camera session with fresh AVCapturePhotoOutput
|
||||||
@ -67,7 +26,7 @@ struct ContentView: View {
|
|||||||
// Camera view - only recreates when sessionKey changes due to Equatable
|
// Camera view - only recreates when sessionKey changes due to Equatable
|
||||||
if !showPhotoReview {
|
if !showPhotoReview {
|
||||||
CameraContainerView(
|
CameraContainerView(
|
||||||
cameraSettings: cameraSettings ?? CameraSettingsState(settings: settings),
|
settings: settings,
|
||||||
sessionKey: cameraSessionKey,
|
sessionKey: cameraSessionKey,
|
||||||
onImageCaptured: { image in
|
onImageCaptured: { image in
|
||||||
capturedPhoto = CapturedPhoto(image: image, timestamp: Date())
|
capturedPhoto = CapturedPhoto(image: image, timestamp: Date())
|
||||||
@ -120,29 +79,16 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
.animation(.easeInOut(duration: Design.Animation.quick), value: showPhotoReview)
|
.animation(.easeInOut(duration: Design.Animation.quick), value: showPhotoReview)
|
||||||
.onAppear {
|
|
||||||
cameraSettings = CameraSettingsState(settings: settings)
|
|
||||||
}
|
|
||||||
.onChange(of: settings.photoQuality) { _, _ in updateCameraSettings() }
|
|
||||||
.onChange(of: settings.isRingLightEnabled) { _, newValue in
|
.onChange(of: settings.isRingLightEnabled) { _, newValue in
|
||||||
updateCameraSettings()
|
|
||||||
if settings.isFlashSyncedWithRingLight {
|
if settings.isFlashSyncedWithRingLight {
|
||||||
settings.flashMode = newValue ? .on : .off
|
settings.flashMode = newValue ? .on : .off
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: settings.lightColor) { _, _ in updateCameraSettings() }
|
|
||||||
.onChange(of: settings.ringSize) { _, _ in updateCameraSettings() }
|
|
||||||
.onChange(of: settings.ringLightOpacity) { _, _ in updateCameraSettings() }
|
|
||||||
.onChange(of: settings.flashMode) { _, _ in updateCameraSettings() }
|
|
||||||
.onChange(of: settings.isFlashSyncedWithRingLight) { _, newValue in
|
.onChange(of: settings.isFlashSyncedWithRingLight) { _, newValue in
|
||||||
updateCameraSettings()
|
|
||||||
if newValue {
|
if newValue {
|
||||||
settings.flashMode = settings.isRingLightEnabled ? .on : .off
|
settings.flashMode = settings.isRingLightEnabled ? .on : .off
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: settings.hdrMode) { _, _ in updateCameraSettings() }
|
|
||||||
.onChange(of: settings.isGridVisible) { _, _ in updateCameraSettings() }
|
|
||||||
.onChange(of: settings.cameraPosition) { _, _ in updateCameraSettings() }
|
|
||||||
.sheet(isPresented: $showSettings) {
|
.sheet(isPresented: $showSettings) {
|
||||||
SettingsView(viewModel: settings, showPaywall: $showPaywall)
|
SettingsView(viewModel: settings, showPaywall: $showPaywall)
|
||||||
}
|
}
|
||||||
@ -151,10 +97,6 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateCameraSettings() {
|
|
||||||
cameraSettings?.update(from: settings)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resets state and regenerates camera session key to create a fresh camera instance
|
/// Resets state and regenerates camera session key to create a fresh camera instance
|
||||||
private func resetCameraForNextCapture() {
|
private func resetCameraForNextCapture() {
|
||||||
capturedPhoto = nil
|
capturedPhoto = nil
|
||||||
@ -169,7 +111,7 @@ struct ContentView: View {
|
|||||||
isSavingPhoto = true
|
isSavingPhoto = true
|
||||||
saveError = nil
|
saveError = nil
|
||||||
|
|
||||||
let quality = cameraSettings?.photoQuality ?? .high
|
let quality = settings.photoQuality
|
||||||
|
|
||||||
Task {
|
Task {
|
||||||
let result = await PhotoLibraryService.savePhotoToLibrary(image, quality: quality)
|
let result = await PhotoLibraryService.savePhotoToLibrary(image, quality: quality)
|
||||||
@ -199,7 +141,7 @@ struct ContentView: View {
|
|||||||
// MARK: - Camera Container 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 {
|
struct CameraContainerView: View, Equatable {
|
||||||
let cameraSettings: CameraSettingsState
|
let settings: SettingsViewModel
|
||||||
let sessionKey: UUID
|
let sessionKey: UUID
|
||||||
let onImageCaptured: (UIImage) -> Void
|
let onImageCaptured: (UIImage) -> Void
|
||||||
|
|
||||||
@ -216,12 +158,12 @@ struct CameraContainerView: View, Equatable {
|
|||||||
cameraManager: cameraManager,
|
cameraManager: cameraManager,
|
||||||
namespace: namespace,
|
namespace: namespace,
|
||||||
closeMCameraAction: closeAction,
|
closeMCameraAction: closeAction,
|
||||||
cameraSettings: cameraSettings,
|
cameraSettings: settings,
|
||||||
onPhotoCaptured: onImageCaptured
|
onPhotoCaptured: onImageCaptured
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.setCapturedMediaScreen(nil)
|
.setCapturedMediaScreen(nil)
|
||||||
.setCameraPosition(cameraSettings.cameraPosition)
|
.setCameraPosition(settings.cameraPosition)
|
||||||
.startSession()
|
.startSession()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,40 +18,10 @@ struct CustomCameraScreen: MCameraScreen {
|
|||||||
let closeMCameraAction: () -> ()
|
let closeMCameraAction: () -> ()
|
||||||
|
|
||||||
/// Shared camera settings state - using Observable class prevents MCamera recreation
|
/// Shared camera settings state - using Observable class prevents MCamera recreation
|
||||||
var cameraSettings: CameraSettingsState
|
var cameraSettings: SettingsViewModel
|
||||||
|
|
||||||
/// Callback when photo is captured - bypasses MijickCamera's callback system
|
/// Callback when photo is captured - bypasses MijickCamera's callback system
|
||||||
var onPhotoCaptured: ((UIImage) -> Void)?
|
var onPhotoCaptured: ((UIImage) -> Void)?
|
||||||
|
|
||||||
// Convenience accessors for settings
|
|
||||||
private var photoQuality: PhotoQuality {
|
|
||||||
get { cameraSettings.photoQuality }
|
|
||||||
nonmutating set { cameraSettings.photoQuality = newValue }
|
|
||||||
}
|
|
||||||
private var isRingLightEnabled: Bool {
|
|
||||||
get { cameraSettings.isRingLightEnabled }
|
|
||||||
nonmutating set { cameraSettings.isRingLightEnabled = newValue }
|
|
||||||
}
|
|
||||||
private var ringLightColor: Color {
|
|
||||||
get { cameraSettings.ringLightColor }
|
|
||||||
nonmutating set { cameraSettings.ringLightColor = newValue }
|
|
||||||
}
|
|
||||||
private var ringLightSize: CGFloat {
|
|
||||||
get { cameraSettings.ringLightSize }
|
|
||||||
nonmutating set { cameraSettings.ringLightSize = newValue }
|
|
||||||
}
|
|
||||||
private var ringLightOpacity: Double {
|
|
||||||
get { cameraSettings.ringLightOpacity }
|
|
||||||
nonmutating set { cameraSettings.ringLightOpacity = newValue }
|
|
||||||
}
|
|
||||||
private var flashMode: CameraFlashMode {
|
|
||||||
get { cameraSettings.flashMode }
|
|
||||||
nonmutating set { cameraSettings.flashMode = newValue }
|
|
||||||
}
|
|
||||||
private var isFlashSyncedWithRingLight: Bool {
|
|
||||||
get { cameraSettings.isFlashSyncedWithRingLight }
|
|
||||||
nonmutating set { cameraSettings.isFlashSyncedWithRingLight = newValue }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Center Stage state
|
// Center Stage state
|
||||||
@State private var isCenterStageEnabled: Bool = AVCaptureDevice.isCenterStageEnabled
|
@State private var isCenterStageEnabled: Bool = AVCaptureDevice.isCenterStageEnabled
|
||||||
@ -98,9 +68,9 @@ struct CustomCameraScreen: MCameraScreen {
|
|||||||
// Ring light overlay - covers corners and creates rounded inner edge
|
// Ring light overlay - covers corners and creates rounded inner edge
|
||||||
// When ring light is off, still show black corners to maintain rounded appearance
|
// When ring light is off, still show black corners to maintain rounded appearance
|
||||||
RingLightOverlay(
|
RingLightOverlay(
|
||||||
color: isRingLightEnabled ? ringLightColor : .black,
|
color: cameraSettings.isRingLightEnabled ? cameraSettings.lightColor : .black,
|
||||||
width: isRingLightEnabled ? ringLightSize : Design.CornerRadius.large,
|
width: cameraSettings.isRingLightEnabled ? cameraSettings.ringSize : Design.CornerRadius.large,
|
||||||
opacity: isRingLightEnabled ? ringLightOpacity : 1.0,
|
opacity: cameraSettings.isRingLightEnabled ? cameraSettings.ringLightOpacity : 1.0,
|
||||||
cornerRadius: Design.CornerRadius.large
|
cornerRadius: Design.CornerRadius.large
|
||||||
)
|
)
|
||||||
.allowsHitTesting(false) // Allow touches to pass through to camera view
|
.allowsHitTesting(false) // Allow touches to pass through to camera view
|
||||||
@ -119,31 +89,31 @@ struct CustomCameraScreen: MCameraScreen {
|
|||||||
isExpanded: $isControlsExpanded,
|
isExpanded: $isControlsExpanded,
|
||||||
hasActiveSettings: hasActiveSettings,
|
hasActiveSettings: hasActiveSettings,
|
||||||
activeSettingsIcons: activeSettingsIcons,
|
activeSettingsIcons: activeSettingsIcons,
|
||||||
flashMode: flashMode,
|
flashMode: cameraSettings.flashMode,
|
||||||
flashIcon: flashIcon,
|
flashIcon: flashIcon,
|
||||||
onFlashTap: toggleFlash,
|
onFlashTap: toggleFlash,
|
||||||
isFlashSyncedWithRingLight: isFlashSyncedWithRingLight,
|
isFlashSyncedWithRingLight: cameraSettings.isFlashSyncedWithRingLight,
|
||||||
onFlashSyncTap: toggleFlashSync,
|
onFlashSyncTap: toggleFlashSync,
|
||||||
hdrMode: cameraSettings.hdrMode,
|
hdrMode: cameraSettings.hdrMode,
|
||||||
hdrIcon: hdrIcon,
|
hdrIcon: hdrIcon,
|
||||||
onHDRTap: toggleHDR,
|
onHDRTap: toggleHDR,
|
||||||
isGridVisible: isGridVisible,
|
isGridVisible: cameraSettings.isGridVisible,
|
||||||
gridIcon: gridIcon,
|
gridIcon: gridIcon,
|
||||||
onGridTap: toggleGrid,
|
onGridTap: toggleGrid,
|
||||||
photoQuality: photoQuality,
|
photoQuality: cameraSettings.photoQuality,
|
||||||
onQualityTap: cycleQuality,
|
onQualityTap: cycleQuality,
|
||||||
isCenterStageAvailable: isCenterStageAvailable,
|
isCenterStageAvailable: isCenterStageAvailable,
|
||||||
isCenterStageEnabled: isCenterStageEnabled,
|
isCenterStageEnabled: isCenterStageEnabled,
|
||||||
onCenterStageTap: toggleCenterStage,
|
onCenterStageTap: toggleCenterStage,
|
||||||
isFrontCamera: cameraPosition == .front,
|
isFrontCamera: cameraPosition == .front,
|
||||||
onFlipCameraTap: flipCamera,
|
onFlipCameraTap: flipCamera,
|
||||||
isRingLightEnabled: isRingLightEnabled,
|
isRingLightEnabled: cameraSettings.isRingLightEnabled,
|
||||||
onRingLightTap: toggleRingLight,
|
onRingLightTap: toggleRingLight,
|
||||||
ringLightColor: ringLightColor,
|
ringLightColor: cameraSettings.lightColor,
|
||||||
onRingLightColorTap: toggleRingLightColorPicker,
|
onRingLightColorTap: toggleRingLightColorPicker,
|
||||||
ringLightSize: ringLightSize,
|
ringLightSize: cameraSettings.ringSize,
|
||||||
onRingLightSizeTap: toggleRingLightSizeSlider,
|
onRingLightSizeTap: toggleRingLightSizeSlider,
|
||||||
ringLightOpacity: ringLightOpacity,
|
ringLightOpacity: cameraSettings.ringLightOpacity,
|
||||||
onRingLightOpacityTap: toggleRingLightOpacitySlider
|
onRingLightOpacityTap: toggleRingLightOpacitySlider
|
||||||
)
|
)
|
||||||
.padding(.horizontal, Design.Spacing.large)
|
.padding(.horizontal, Design.Spacing.large)
|
||||||
@ -169,31 +139,31 @@ struct CustomCameraScreen: MCameraScreen {
|
|||||||
isExpanded: $isControlsExpanded,
|
isExpanded: $isControlsExpanded,
|
||||||
hasActiveSettings: hasActiveSettings,
|
hasActiveSettings: hasActiveSettings,
|
||||||
activeSettingsIcons: activeSettingsIcons,
|
activeSettingsIcons: activeSettingsIcons,
|
||||||
flashMode: flashMode,
|
flashMode: cameraSettings.flashMode,
|
||||||
flashIcon: flashIcon,
|
flashIcon: flashIcon,
|
||||||
onFlashTap: toggleFlash,
|
onFlashTap: toggleFlash,
|
||||||
isFlashSyncedWithRingLight: isFlashSyncedWithRingLight,
|
isFlashSyncedWithRingLight: cameraSettings.isFlashSyncedWithRingLight,
|
||||||
onFlashSyncTap: toggleFlashSync,
|
onFlashSyncTap: toggleFlashSync,
|
||||||
hdrMode: cameraSettings.hdrMode,
|
hdrMode: cameraSettings.hdrMode,
|
||||||
hdrIcon: hdrIcon,
|
hdrIcon: hdrIcon,
|
||||||
onHDRTap: toggleHDR,
|
onHDRTap: toggleHDR,
|
||||||
isGridVisible: isGridVisible,
|
isGridVisible: cameraSettings.isGridVisible,
|
||||||
gridIcon: gridIcon,
|
gridIcon: gridIcon,
|
||||||
onGridTap: toggleGrid,
|
onGridTap: toggleGrid,
|
||||||
photoQuality: photoQuality,
|
photoQuality: cameraSettings.photoQuality,
|
||||||
onQualityTap: cycleQuality,
|
onQualityTap: cycleQuality,
|
||||||
isCenterStageAvailable: isCenterStageAvailable,
|
isCenterStageAvailable: isCenterStageAvailable,
|
||||||
isCenterStageEnabled: isCenterStageEnabled,
|
isCenterStageEnabled: isCenterStageEnabled,
|
||||||
onCenterStageTap: toggleCenterStage,
|
onCenterStageTap: toggleCenterStage,
|
||||||
isFrontCamera: cameraPosition == .front,
|
isFrontCamera: cameraPosition == .front,
|
||||||
onFlipCameraTap: flipCamera,
|
onFlipCameraTap: flipCamera,
|
||||||
isRingLightEnabled: isRingLightEnabled,
|
isRingLightEnabled: cameraSettings.isRingLightEnabled,
|
||||||
onRingLightTap: toggleRingLight,
|
onRingLightTap: toggleRingLight,
|
||||||
ringLightColor: ringLightColor,
|
ringLightColor: cameraSettings.lightColor,
|
||||||
onRingLightColorTap: toggleRingLightColorPicker,
|
onRingLightColorTap: toggleRingLightColorPicker,
|
||||||
ringLightSize: ringLightSize,
|
ringLightSize: cameraSettings.ringSize,
|
||||||
onRingLightSizeTap: toggleRingLightSizeSlider,
|
onRingLightSizeTap: toggleRingLightSizeSlider,
|
||||||
ringLightOpacity: ringLightOpacity,
|
ringLightOpacity: cameraSettings.ringLightOpacity,
|
||||||
onRingLightOpacityTap: toggleRingLightOpacitySlider
|
onRingLightOpacityTap: toggleRingLightOpacitySlider
|
||||||
)
|
)
|
||||||
.padding(.horizontal, Design.Spacing.large)
|
.padding(.horizontal, Design.Spacing.large)
|
||||||
@ -222,8 +192,8 @@ struct CustomCameraScreen: MCameraScreen {
|
|||||||
if showRingLightColorPicker {
|
if showRingLightColorPicker {
|
||||||
ColorPickerOverlay(
|
ColorPickerOverlay(
|
||||||
selectedColor: Binding(
|
selectedColor: Binding(
|
||||||
get: { cameraSettings.ringLightColor },
|
get: { cameraSettings.selectedLightColor.color },
|
||||||
set: { cameraSettings.ringLightColor = $0 }
|
set: { cameraSettings.selectedLightColor = RingLightColor.custom(with: $0) }
|
||||||
),
|
),
|
||||||
isPresented: $showRingLightColorPicker
|
isPresented: $showRingLightColorPicker
|
||||||
)
|
)
|
||||||
@ -234,8 +204,8 @@ struct CustomCameraScreen: MCameraScreen {
|
|||||||
if showRingLightSizeSlider {
|
if showRingLightSizeSlider {
|
||||||
SizeSliderOverlay(
|
SizeSliderOverlay(
|
||||||
selectedSize: Binding(
|
selectedSize: Binding(
|
||||||
get: { cameraSettings.ringLightSize },
|
get: { cameraSettings.ringSize },
|
||||||
set: { cameraSettings.ringLightSize = $0 }
|
set: { cameraSettings.ringSize = $0 }
|
||||||
),
|
),
|
||||||
isPresented: $showRingLightSizeSlider
|
isPresented: $showRingLightSizeSlider
|
||||||
)
|
)
|
||||||
@ -290,7 +260,7 @@ struct CustomCameraScreen: MCameraScreen {
|
|||||||
// Initialize zoom gesture state
|
// Initialize zoom gesture state
|
||||||
lastMagnification = zoomFactor
|
lastMagnification = zoomFactor
|
||||||
}
|
}
|
||||||
.onChange(of: isFlashSyncedWithRingLight) { _, _ in
|
.onChange(of: cameraSettings.isFlashSyncedWithRingLight) { _, _ in
|
||||||
// Only update when sync setting changes, not on every color change
|
// Only update when sync setting changes, not on every color change
|
||||||
updateFlashSyncState()
|
updateFlashSyncState()
|
||||||
}
|
}
|
||||||
@ -309,22 +279,22 @@ struct CustomCameraScreen: MCameraScreen {
|
|||||||
|
|
||||||
/// Returns true if any setting is in a non-default state
|
/// Returns true if any setting is in a non-default state
|
||||||
private var hasActiveSettings: Bool {
|
private var hasActiveSettings: Bool {
|
||||||
flashMode != .off || cameraSettings.hdrMode != .off || isGridVisible || isCenterStageEnabled || isRingLightEnabled
|
cameraSettings.flashMode != .off || cameraSettings.hdrMode != .off || cameraSettings.isGridVisible || isCenterStageEnabled || cameraSettings.isRingLightEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns icons for currently active settings (for collapsed pill display)
|
/// Returns icons for currently active settings (for collapsed pill display)
|
||||||
private var activeSettingsIcons: [String] {
|
private var activeSettingsIcons: [String] {
|
||||||
var icons: [String] = []
|
var icons: [String] = []
|
||||||
if flashMode != .off {
|
if cameraSettings.flashMode != .off {
|
||||||
icons.append(flashIcon)
|
icons.append(flashIcon)
|
||||||
}
|
}
|
||||||
if cameraSettings.hdrMode != .off {
|
if cameraSettings.hdrMode != .off {
|
||||||
icons.append(hdrIcon)
|
icons.append(hdrIcon)
|
||||||
}
|
}
|
||||||
if isGridVisible {
|
if cameraSettings.isGridVisible {
|
||||||
icons.append(gridIcon)
|
icons.append(gridIcon)
|
||||||
}
|
}
|
||||||
if isRingLightEnabled {
|
if cameraSettings.isRingLightEnabled {
|
||||||
icons.append("circle.fill")
|
icons.append("circle.fill")
|
||||||
}
|
}
|
||||||
if isCenterStageEnabled {
|
if isCenterStageEnabled {
|
||||||
@ -335,7 +305,7 @@ struct CustomCameraScreen: MCameraScreen {
|
|||||||
|
|
||||||
// MARK: - Control Icons
|
// MARK: - Control Icons
|
||||||
private var flashIcon: String {
|
private var flashIcon: String {
|
||||||
flashMode.icon
|
cameraSettings.flashMode.icon
|
||||||
}
|
}
|
||||||
|
|
||||||
private var hdrIcon: String {
|
private var hdrIcon: String {
|
||||||
@ -347,7 +317,7 @@ struct CustomCameraScreen: MCameraScreen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var gridIcon: String {
|
private var gridIcon: String {
|
||||||
isGridVisible ? "grid" : "grid"
|
cameraSettings.isGridVisible ? "grid" : "grid"
|
||||||
}
|
}
|
||||||
|
|
||||||
private var isCenterStageAvailable: Bool {
|
private var isCenterStageAvailable: Bool {
|
||||||
@ -360,18 +330,18 @@ struct CustomCameraScreen: MCameraScreen {
|
|||||||
// MARK: - Actions
|
// MARK: - Actions
|
||||||
private func toggleFlash() {
|
private func toggleFlash() {
|
||||||
let nextMode: CameraFlashMode
|
let nextMode: CameraFlashMode
|
||||||
switch flashMode {
|
switch cameraSettings.flashMode {
|
||||||
case .off: nextMode = .auto
|
case .off: nextMode = .auto
|
||||||
case .auto: nextMode = .on
|
case .auto: nextMode = .on
|
||||||
case .on: nextMode = .off
|
case .on: nextMode = .off
|
||||||
}
|
}
|
||||||
flashMode = nextMode
|
cameraSettings.flashMode = nextMode
|
||||||
// Update MijickCamera's flash mode so it knows to use iOS Retina Flash
|
// Update MijickCamera's flash mode so it knows to use iOS Retina Flash
|
||||||
setFlashMode(nextMode.toMijickFlashMode)
|
setFlashMode(nextMode.toMijickFlashMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func toggleFlashSync() {
|
private func toggleFlashSync() {
|
||||||
isFlashSyncedWithRingLight.toggle()
|
cameraSettings.isFlashSyncedWithRingLight.toggle()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func toggleHDR() {
|
private func toggleHDR() {
|
||||||
@ -392,7 +362,8 @@ struct CustomCameraScreen: MCameraScreen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func toggleGrid() {
|
private func toggleGrid() {
|
||||||
setGridVisibility(!isGridVisible)
|
cameraSettings.isGridVisible.toggle()
|
||||||
|
setGridVisibility(cameraSettings.isGridVisible)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func flipCamera() {
|
private func flipCamera() {
|
||||||
@ -400,6 +371,7 @@ struct CustomCameraScreen: MCameraScreen {
|
|||||||
do {
|
do {
|
||||||
let newPosition: CameraPosition = (cameraPosition == .front) ? .back : .front
|
let newPosition: CameraPosition = (cameraPosition == .front) ? .back : .front
|
||||||
try await setCameraPosition(newPosition)
|
try await setCameraPosition(newPosition)
|
||||||
|
cameraSettings.cameraPosition = newPosition
|
||||||
} catch {
|
} catch {
|
||||||
print("Failed to flip camera: \(error)")
|
print("Failed to flip camera: \(error)")
|
||||||
}
|
}
|
||||||
@ -442,34 +414,34 @@ struct CustomCameraScreen: MCameraScreen {
|
|||||||
|
|
||||||
private func cycleQuality() {
|
private func cycleQuality() {
|
||||||
let allCases = PhotoQuality.allCases
|
let allCases = PhotoQuality.allCases
|
||||||
let currentIndex = allCases.firstIndex(of: photoQuality) ?? 0
|
let currentIndex = allCases.firstIndex(of: cameraSettings.photoQuality) ?? 0
|
||||||
let nextIndex = (currentIndex + 1) % allCases.count
|
let nextIndex = (currentIndex + 1) % allCases.count
|
||||||
photoQuality = allCases[nextIndex]
|
cameraSettings.photoQuality = allCases[nextIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
private func toggleRingLight() {
|
private func toggleRingLight() {
|
||||||
isRingLightEnabled.toggle()
|
cameraSettings.isRingLightEnabled.toggle()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateFlashSyncState() {
|
private func updateFlashSyncState() {
|
||||||
// Tell MijickCamera whether we're handling flash ourselves (sync enabled)
|
// Tell MijickCamera whether we're handling flash ourselves (sync enabled)
|
||||||
// or if iOS should handle it (sync disabled)
|
// or if iOS should handle it (sync disabled)
|
||||||
// We use .white as a placeholder - the actual color comes from ringLightColor in SwiftUI
|
// We use .white as a placeholder - the actual color comes from ringLightColor in SwiftUI
|
||||||
if isFlashSyncedWithRingLight {
|
if cameraSettings.isFlashSyncedWithRingLight {
|
||||||
setScreenFlashColor(.white) // Non-nil = we handle flash, disable iOS flash
|
setScreenFlashColor(.white) // Non-nil = we handle flash, disable iOS flash
|
||||||
} else {
|
} else {
|
||||||
setScreenFlashColor(nil) // nil = let iOS handle Retina Flash
|
setScreenFlashColor(nil) // nil = let iOS handle Retina Flash
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The color to use for screen flash overlay
|
/// The color to use for screen flash overlay
|
||||||
private var screenFlashColor: Color {
|
private var screenFlashColor: Color {
|
||||||
isFlashSyncedWithRingLight ? ringLightColor : .white
|
cameraSettings.isFlashSyncedWithRingLight ? cameraSettings.lightColor : .white
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether to use custom screen flash (front camera + flash on + sync enabled)
|
/// Whether to use custom screen flash (front camera + flash on + sync enabled)
|
||||||
private var shouldUseCustomScreenFlash: Bool {
|
private var shouldUseCustomScreenFlash: Bool {
|
||||||
cameraPosition == .front && flashMode != .off && isFlashSyncedWithRingLight
|
cameraPosition == .front && cameraSettings.flashMode != .off && cameraSettings.isFlashSyncedWithRingLight
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Performs capture with screen flash if needed
|
/// Performs capture with screen flash if needed
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user