Compare commits

..

No commits in common. "19e17b7051fcf6064f78d17dde9bd78d29aefb26" and "815b91f6caca4d8fc3f60f07a030570aad2b5207" have entirely different histories.

4 changed files with 15 additions and 91 deletions

View File

@ -28,7 +28,6 @@ struct ContentView: View {
EquatableView(content: CameraContainerView( EquatableView(content: CameraContainerView(
settings: settings, settings: settings,
sessionKey: cameraSessionKey, sessionKey: cameraSessionKey,
cameraPosition: settings.cameraPosition,
onImageCaptured: { image in onImageCaptured: { image in
handlePhotoCaptured(image) handlePhotoCaptured(image)
} }
@ -80,10 +79,6 @@ struct ContentView: View {
settings.flashMode = settings.isRingLightEnabled ? .on : .off settings.flashMode = settings.isRingLightEnabled ? .on : .off
} }
} }
.onChange(of: settings.cameraPosition) { _, _ in
// Force camera session recreation when camera position changes
cameraSessionKey = UUID()
}
.sheet(isPresented: $showSettings) { .sheet(isPresented: $showSettings) {
SettingsView(viewModel: settings, showPaywall: $showPaywall) SettingsView(viewModel: settings, showPaywall: $showPaywall)
} }
@ -167,7 +162,6 @@ struct ContentView: View {
struct CameraContainerView: View, Equatable { struct CameraContainerView: View, Equatable {
let settings: SettingsViewModel let settings: SettingsViewModel
let sessionKey: UUID let sessionKey: UUID
let cameraPosition: CameraPosition
let onImageCaptured: (UIImage) -> Void let onImageCaptured: (UIImage) -> Void
// Only compare sessionKey for equality - ignore settings and callback changes // Only compare sessionKey for equality - ignore settings and callback changes
@ -176,7 +170,7 @@ struct CameraContainerView: View, Equatable {
} }
var body: some View { var body: some View {
let _ = Design.debugLog("CameraContainerView body evaluated - sessionKey: \(sessionKey), position: \(cameraPosition)") let _ = Design.debugLog("CameraContainerView body evaluated - sessionKey: \(sessionKey)")
MCamera() MCamera()
.setCameraScreen { cameraManager, namespace, closeAction in .setCameraScreen { cameraManager, namespace, closeAction in
CustomCameraScreen( CustomCameraScreen(
@ -188,7 +182,9 @@ struct CameraContainerView: View, Equatable {
) )
} }
.setCapturedMediaScreen(nil) .setCapturedMediaScreen(nil)
.setCameraPosition(cameraPosition) // Use front camera as default for selfie app - don't read from settings here
// to avoid triggering @Observable tracking which breaks the camera
.setCameraPosition(.front)
.startSession() .startSession()
} }
} }

View File

@ -770,7 +770,10 @@ struct SettingsView: View {
SettingsToggle( SettingsToggle(
title: "Enable Debug Premium", title: "Enable Debug Premium",
subtitle: "Unlock all premium features for testing", subtitle: "Unlock all premium features for testing",
isOn: $viewModel.isDebugPremiumEnabled isOn: Binding(
get: { viewModel.premiumManager.isDebugPremiumToggleEnabled },
set: { viewModel.premiumManager.isDebugPremiumToggleEnabled = $0 }
)
) )
.tint(Color.Status.warning) .tint(Color.Status.warning)
// Icon Generator // Icon Generator

View File

@ -85,20 +85,12 @@ final class SettingsViewModel: RingLightConfigurable {
static let defaultRingSize: CGFloat = 40 static let defaultRingSize: CGFloat = 40
// MARK: - Premium Manager // MARK: - Premium Manager
/// Premium manager for checking subscription status /// Premium manager for checking subscription status
@ObservationIgnored private let premiumManager = PremiumManager() private let premiumManager = PremiumManager()
/// Whether the user has premium access (stored property for proper UI updates) /// Whether the user has premium access
private var _isPremiumUnlocked: Bool = false var isPremiumUnlocked: Bool { premiumManager.isPremiumUnlocked }
/// Whether the user has premium access (observable for UI updates)
var isPremiumUnlocked: Bool {
get { _isPremiumUnlocked }
set {
_isPremiumUnlocked = newValue
}
}
// MARK: - Cloud Sync Manager // MARK: - Cloud Sync Manager
@ -342,71 +334,6 @@ final class SettingsViewModel: RingLightConfigurable {
var isCustomColorSelected: Bool { var isCustomColorSelected: Bool {
lightColorId == RingLightColor.customId lightColorId == RingLightColor.customId
} }
// MARK: - Debug Premium Toggle
/// Debug premium toggle for testing (DEBUG builds only)
var isDebugPremiumEnabled: Bool {
get { premiumManager.isDebugPremiumToggleEnabled }
set {
let wasPremium = premiumManager.isDebugPremiumToggleEnabled
premiumManager.isDebugPremiumToggleEnabled = newValue
// Update premium status for UI refresh
isPremiumUnlocked = premiumManager.isPremiumUnlocked
// Reset premium settings when toggling OFF
if wasPremium && !newValue {
resetPremiumSettingsToDefaults()
}
}
}
/// Reset premium-only settings to their free defaults when debug premium is disabled
private func resetPremiumSettingsToDefaults() {
// Clear cached values that depend on premium status
_cachedRingSize = nil
_cachedLightColorId = nil
_cachedCustomColor = nil
// Reset premium settings to defaults (bypass premium gates for direct reset)
updateSettings { settings in
if settings.lightColorId != Self.defaultFreeColorId {
settings.lightColorId = Self.defaultFreeColorId
}
if settings.isMirrorFlipped {
settings.isMirrorFlipped = false
}
if settings.isSkinSmoothingEnabled {
settings.isSkinSmoothingEnabled = false
}
if settings.isFlashSyncedWithRingLight {
settings.isFlashSyncedWithRingLight = false
}
if settings.hdrModeRaw != CameraHDRMode.off.rawValue {
settings.hdrModeRaw = CameraHDRMode.off.rawValue
}
if settings.photoQualityRaw != PhotoQuality.medium.rawValue {
settings.photoQualityRaw = PhotoQuality.medium.rawValue
}
if settings.selectedTimerRaw != TimerOption.three.rawValue {
settings.selectedTimerRaw = TimerOption.three.rawValue
}
if settings.isCenterStageEnabled {
settings.isCenterStageEnabled = false
}
}
// Force sync to ensure changes are saved
forceSync()
}
/// Sets the custom color and selects it (PREMIUM) /// Sets the custom color and selects it (PREMIUM)
func selectCustomColor(_ color: Color) { func selectCustomColor(_ color: Color) {
@ -436,10 +363,8 @@ final class SettingsViewModel: RingLightConfigurable {
var hasCompletedInitialSync: Bool { cloudSync.hasCompletedInitialSync } var hasCompletedInitialSync: Bool { cloudSync.hasCompletedInitialSync }
// MARK: - Initialization // MARK: - Initialization
init() { init() {
// Initialize premium status
_isPremiumUnlocked = premiumManager.isPremiumUnlocked
// CloudSyncManager handles syncing automatically // CloudSyncManager handles syncing automatically
} }

View File

@ -27,7 +27,7 @@ final class PremiumManager: PremiumManaging {
// MARK: - Debug Override // MARK: - Debug Override
/// Debug premium toggle stored in UserDefaults (only available in DEBUG builds) /// Debug premium toggle stored in UserDefaults (only available in DEBUG builds)
@AppStorage("debugPremiumEnabled") @ObservationIgnored private var debugPremiumEnabled = false @AppStorage("debugPremiumEnabled") private var debugPremiumEnabled = false
/// Check if debug premium is enabled via UserDefaults toggle or environment variable. /// Check if debug premium is enabled via UserDefaults toggle or environment variable.
/// The toggle in Settings > Debug takes precedence over environment variables. /// The toggle in Settings > Debug takes precedence over environment variables.