- Camera preview now uses 4:3 aspect ratio (matches photo capture)
- Camera is centered both horizontally and vertically
- Ring light background properly visible around camera
- Controls positioned correctly with safe area handling
- Grid overlay now clips to camera bounds
- Improved control bar layout with proper spacing
- Add MijickCamera package for camera handling
- Create RingLightCameraScreen conforming to MCameraScreen protocol
- Ring light background fills screen with settings.lightColor
- Camera preview padded inward to create ring effect
- Custom capture button and controls overlay
- Grid overlay support
- Camera flip button using MijickCamera API
- Delete old CameraViewModel and CameraPreview (replaced by MijickCamera)
- Simplified PostCapturePreviewView for photo/video preview
MijickCamera wasn't rendering the camera preview properly in our
view hierarchy. Reverting to our custom AVFoundation-based camera
implementation which was working correctly.
Reverted:
- Restored CameraViewModel.swift
- Restored CameraPreview.swift
- Restored ContentView.swift to pre-MijickCamera version
- Removed MijickCamera package dependency
Kept:
- Open Source Licenses section (now just shows RevenueCat)
- All other features and fixes
Our custom camera code handles:
- Camera preview with proper orientation
- Photo/video capture
- Front flash effect
- Center Stage support
- Manual rotation
- Zoom gestures
Issue: MCamera wasn't rendering when embedded inside ZStack with
background color in front of it.
Solution: Restructure view hierarchy:
- MCamera is now the base view (not inside a ZStack)
- Ring light effect is now an overlay using mask/blendMode
- Grid, controls, and toast are overlays on top
The ring light overlay uses:
1. Full-screen settings.lightColor
2. A mask with destinationOut blend mode
3. A RoundedRectangle cutout in the center
This allows MCamera to render properly while creating the ring
light border effect around the camera preview.
Center Stage is a device-level Apple feature that works independently
of any camera framework. Added:
- Center Stage button in top control bar (person.crop.rectangle icon)
- checkCenterStageAvailability() checks device.activeFormat.isCenterStageSupported
- toggleCenterStage() uses AVCaptureDevice.isCenterStageEnabled
- Button only appears on devices that support Center Stage
- Yellow highlight when enabled
Works with MijickCamera since Center Stage is controlled at the
AVCaptureDevice level, not the camera view level.
Apache 2.0 license requires attribution for MijickCamera.
Added:
- 'About' section in Settings with 'Open Source Licenses' link
- LicensesView showing all third-party libraries:
- MijickCamera (Apache 2.0)
- RevenueCat (MIT)
- Links to GitHub repositories
- License type badges
This fulfills the attribution requirement for Apache 2.0 licensed
libraries used in the app.
Major refactor: Replace custom camera implementation with MijickCamera
Added:
- MijickCamera Swift package (v3.0.3)
- MijickTimer dependency (required by MijickCamera)
Changed:
- ContentView now uses MCamera() from MijickCamera
- Ring light wraps around MijickCamera view with padding
- MijickCamera handles all camera logic:
- Permissions
- Capture (photo/video)
- Camera switching
- Orientation/rotation
- Zoom/focus gestures
- Flash
Removed:
- CameraViewModel.swift (replaced by MijickCamera)
- CameraPreview.swift (replaced by MijickCamera)
Kept:
- Ring light background (settings.lightColor)
- Ring size control (settings.ringSize)
- Grid overlay
- Post-capture preview workflow
- Settings view
- Premium features and paywall
- iCloud sync
Benefits:
- Less code to maintain
- Battle-tested camera implementation
- Better rotation handling built-in
- More camera features available (filters, exposure, etc.)
New feature: Rotate preview independent of device orientation
- Rotate button in top control bar (next to Center Stage)
- Cycles through: 0° → 90° → 180° → 270° → 0°
- Yellow highlight when rotation is active
- Icon changes to show current rotation state
Ring light integration:
- Preview background color now matches ring light color
- Letterbox areas (from aspect ratio differences) show ring light
- Placeholder during permission request also uses ring light color
Visual feedback:
- rotate.right (outline) = no rotation
- rotate.right.fill = 90° right
- arrow.up.arrow.down = 180°
- rotate.left.fill = 270° (90° left)
Full accessibility support with labels and hints.
Issues fixed:
1. On app launch, UIDevice.current.orientation may be .unknown or .faceUp
causing no orientation to be set (defaulting to landscape)
2. When phone is flat, orientation was being skipped
Solution:
- Track lastValidOrientation as fallback
- When device orientation is invalid, get from windowScene.interfaceOrientation
- Use last known good orientation if all else fails
- Default to portrait (90°) if nothing else works
This ensures the camera preview starts in the correct orientation
and stays properly rotated during use.
Changes:
1. Preview layer now uses .resizeAspect instead of .resizeAspectFill
- Shows exactly what will be in the captured photo
- No cropping - what you see is what you get
- Ring light naturally fills any letterbox areas
2. Session preset changed from .high to .photo
- Optimized for photo capture
- Consistent 4:3 aspect ratio
- Better quality for selfies
This ensures the preview accurately represents the final photo,
eliminating surprise cropping in captured images.
The preview layer's connection needs its own rotation update, separate
from the capture output connections.
Changes:
- CameraPreviewUIView now listens to UIDevice.orientationDidChangeNotification
- updatePreviewOrientation() updates the preview layer's connection
- Called on layoutSubviews and orientation changes
- Handles faceUp/faceDown/unknown by keeping current orientation
- Uses modern videoRotationAngle API (iOS 17+)
Visual feedback for non-premium users:
- Premium colors show lock overlay with darkened circle
- Crown icon is hollow (outline) when locked, filled when unlocked
- Text is dimmed for locked colors
- Custom color shows rainbow gradient with lock overlay
Interaction behavior:
- Tapping locked premium color opens paywall
- Tapping locked custom color opens paywall
- Non-premium presets (Pure White, Warm Cream) remain fully accessible
- Premium users see unlocked UI with filled crown icons
This helps users:
1. See what premium features are available
2. Easily distinguish free vs premium colors
3. Test both states by toggling ENABLE_DEBUG_PREMIUM env var
Bug: The ring light background was gated behind premium check:
premiumManager.isPremiumUnlocked ? settings.lightColor : white
This blocked ALL colors (even non-premium ones like Warm Cream)
from displaying unless the user was premium.
Fix: Remove the premium gate from the display - the selected color
always shows. Premium enforcement should happen in Settings when
selecting colors, not in displaying them.
Issue: SwiftUI observation wasn't tracking color changes properly
Fixes:
1. Removed intermediate 'settings' computed property in ContentView
- Was breaking SwiftUI's observation chain
- Now access viewModel.settings directly everywhere
2. Added cached lightColorId for immediate UI response
- Similar pattern to ringSize caching
- Ensures SwiftUI tracks the stored property changes
This ensures the ring light color updates immediately when
selecting a different color preset or custom color in settings.
Fixes:
1. Front flash now properly resets after capture
- restorePreviewAfterFlash() called in photo delegate
- Preview no longer stays white after taking photo
2. Device rotation support
- updateVideoOrientation() updates capture connections
- Uses modern videoRotationAngle API (iOS 17+)
- Listens to UIDevice.orientationDidChangeNotification
3. Center Stage support for supported devices
- Detects Center Stage availability on front camera
- Toggle button in top control bar (person.crop.rectangle icon)
- Yellow highlight when enabled
- Updates availability on camera switch
Fixes:
1. Camera preview rounded corners - clipShape now applied before padding
so the preview itself has rounded corners, not the container
2. Debounced slider saves - ringSize and customColor now use debouncing
- Immediate UI update via cached values
- 300ms debounce before cloud save
- Prevents excessive save operations during slider drag
3. Simplified custom color picker to one-step
- ColorPicker styled as a circle button
- Shows current custom color always (no rainbow)
- Tapping opens iOS native color picker directly
- Color applies immediately on selection
- No Apply/Cancel sheet needed
Features:
- Custom color button in Light Color section (rainbow gradient icon)
- Tapping opens color picker sheet with:
- Live color preview
- Native iOS ColorPicker
- Tips for best ring light colors
- Custom color syncs across devices via iCloud
- Premium-gated with crown icon indicator
Storage:
- CustomColorRGB struct for Codable-compatible color storage
- RGB values stored separately in SyncedSettings
- Color converts to/from UIColor for RGB extraction
UI:
- Rainbow gradient when not selected, solid custom color when selected
- Sheet with Apply/Cancel buttons
- Color preview bar at top of picker
Changes:
1. Camera preview now fills available space (not forced square)
- Maintains proper aspect ratio for captured photos
- Controls overlay on top of preview
2. Ring size now limited based on screen dimensions
- Maximum is 1/4 of smaller screen dimension
- Prevents content from shifting off-screen
3. Removed light intensity slider
- Was causing color changes (opacity approach)
- Ring light now always at full brightness
4. Removed crown icon from main screen
- Pro upgrade moved to Settings > Pro section
- Cleaner camera interface
5. Smaller top icons
- Grid and settings buttons use .body font
- Less visual clutter
Features:
- Full-screen PostCapturePreviewView after photo/video capture
- Auto-save to Photo Library (on by default, configurable in Settings)
- Toast notification when saved
- Retake button to discard and return to camera
- Share button with native iOS Share Sheet
- Edit mode with smoothing and glow intensity sliders
- Premium tools teaser in edit view
- Video/boomerang auto-playback with loop support
Settings:
- Added 'Auto-Save' toggle in Capture section
- Syncs across devices via iCloud
Architecture:
- CapturedMedia enum for photo/video/boomerang types
- ShareSheet UIViewControllerRepresentable wrapper
- Toast system in CameraViewModel