8.9 KiB
8.9 KiB
AI Implementation Guide
How This App Was Architected & Built
This project was developed following strict senior-level iOS engineering standards, with guidance from AI assistants acting as Senior iOS Engineers specializing in SwiftUI and modern Apple frameworks.
Guiding Principles (from AGENTS.md)
- Protocol-Oriented Programming (POP) first: All shared capabilities defined via protocols before concrete types
- MVVM-lite: Views are "dumb" — all logic lives in
@Observableview models - Bedrock Design System: Centralized design tokens, no magic numbers
- Full accessibility: Dynamic Type, VoiceOver labels/hints/traits/announcements
- Modern Swift & SwiftUI: Swift 6 concurrency,
@MainActor,foregroundStyle,clipShape(.rect),NavigationStack - Testable & reusable design: Protocols enable mocking and future package extraction
Architecture Overview
Shared/
├── DesignConstants.swift → Uses Bedrock design tokens
├── BrandingConfig.swift → App icon & launch screen config
├── Color+Extensions.swift → Ring light color presets
├── Models/
│ ├── CameraFlashMode.swift → Flash mode enum
│ ├── CameraHDRMode.swift → HDR mode enum
│ ├── PhotoQuality.swift → Photo quality settings
│ └── CapturedPhoto.swift → Photo data model
├── Protocols/
│ ├── RingLightConfigurable.swift → Border, color, brightness
│ ├── CaptureControlling.swift → Timer, grid, zoom, capture
│ └── PremiumManaging.swift → Subscription state
├── Premium/
│ └── PremiumManager.swift → RevenueCat integration
├── Services/
│ └── PhotoLibraryService.swift → Photo saving service
└── Storage/
└── SyncedSettings.swift → iCloud-synced settings
Features/
├── Camera/ → Main camera UI
│ ├── ContentView.swift → Screen coordinator
│ ├── Views/ → UI components
│ └── GridOverlay.swift → Rule of thirds
├── Settings/ → Configuration
│ ├── SettingsView.swift → Settings UI
│ └── SettingsViewModel.swift → Settings logic + sync
└── Paywall/ → Pro subscription flow
Key Implementation Decisions
1. Ring Light Effect
- Achieved using
RingLightOverlayview that creates a colored border around the camera preview - Border width controlled via user setting (10-120pt range)
- Multiple preset colors with premium custom color picker
- Adjustable opacity/brightness (10%-100%)
- Enabled/disabled toggle for quick access
2. Camera System
- Uses MijickCamera framework for SwiftUI-native camera handling
- Supports front and back camera switching
- Pinch-to-zoom with smooth interpolation
- Flash modes: Off, On, Auto (with premium flash sync)
- HDR mode support (premium feature)
- Photo quality settings (medium free, high premium)
3. Capture Enhancements
- Self-timer with countdown (3s free, 5s/10s premium)
- Post-capture preview with share functionality
- Auto-save option to Photo Library
- Front flash using screen brightness
4. Freemium Model
- Built with RevenueCat for subscription management
PremiumManagerwraps RevenueCat SDKPremiumGateutility for clean premium feature access- Settings automatically fall back to free defaults when not premium
5. iCloud Sync
- Uses Bedrock's CloudSyncManager for settings synchronization
SyncedSettingsmodel contains all user preferences- Debounced saves for slider values (300ms delay)
- Real-time sync status display in Settings
- Available to all users (not a premium feature)
6. Branding System
- Uses Bedrock's Branding module for launch screen and app icon
BrandingConfig.swiftdefines app-specific colors and symbolsLaunchBackground.colorsetmatches launch screen primary color- Animated launch with configurable duration and pattern style
- Icon generator available in DEBUG builds
Premium Feature Implementation
How Premium Gating Works
The app uses a centralized PremiumGate utility for consistent premium feature handling:
// In SettingsViewModel
var isMirrorFlipped: Bool {
get { PremiumGate.get(cloudSync.data.isMirrorFlipped, default: false, isPremium: isPremiumUnlocked) }
set {
guard PremiumGate.canSet(isPremium: isPremiumUnlocked) else { return }
updateSettings { $0.isMirrorFlipped = newValue }
}
}
Premium Features List
| Feature | Free Value | Premium Value |
|---|---|---|
| Ring light colors | Pure White, Warm Cream | All presets + custom |
| Timer options | Off, 3s | Off, 3s, 5s, 10s |
| Photo quality | Medium | Medium, High |
| HDR mode | Off | Off, On, Auto |
| True mirror | Off | Configurable |
| Skin smoothing | Off | Configurable |
| Flash sync | Off | Configurable |
| Center stage | Off | Configurable |
Settings & Persistence
SyncedSettings Model
All user preferences are stored in a single SyncedSettings struct that syncs via iCloud:
- Ring light: size, color ID, custom color RGB, opacity, enabled
- Camera: position, flash mode, HDR mode, photo quality
- Display: mirror flip, skin smoothing, grid visible
- Capture: timer, capture mode, auto-save
- Premium features: flash sync, center stage
Debounced Saves
Slider values (ring size, opacity) use debounced saving to prevent excessive iCloud writes:
private func debouncedSave(key: String, action: @escaping () -> Void) {
debounceTask?.cancel()
debounceTask = Task {
try? await Task.sleep(for: .milliseconds(300))
guard !Task.isCancelled else { return }
action()
}
}
Branding Implementation
Files Involved
- BrandingConfig.swift - Defines app icon and launch screen configurations
- LaunchBackground.colorset - Asset catalog color matching primary brand color
- SelfieCamApp.swift - Wraps ContentView with AppLaunchView
Color Scheme
extension Color {
enum Branding {
static let primary = Color(red: 0.85, green: 0.25, blue: 0.45) // Vibrant magenta
static let secondary = Color(red: 0.45, green: 0.12, blue: 0.35) // Deep purple
static let accent = Color.white
}
}
Launch Screen Configuration
static let selfieCam = LaunchScreenConfig(
title: "SELFIE CAM",
tagline: "Look Your Best",
iconSymbols: ["camera.fill", "sparkles"],
cornerSymbol: "sparkle",
patternStyle: .radial,
// ... colors and sizing
)
Development Workflow
Adding a New Feature
- Define the protocol (if shared behavior)
- Add to SyncedSettings (if needs persistence)
- Implement in SettingsViewModel (with premium gating if applicable)
- Add UI in SettingsView
- Update documentation (README, this file)
Adding a Premium Feature
- Add setting to
SyncedSettingswith appropriate default - Use
PremiumGate.get()for the getter with free default - Use
PremiumGate.canSet()guard for the setter - Add premium indicator (crown icon) in UI
- Wire up paywall trigger for non-premium users
Testing Premium Features
Set environment variable in scheme:
- Name:
ENABLE_DEBUG_PREMIUM - Value:
1
Reusability & Extraction
The codebase is structured for future extraction into reusable packages:
| Potential Package | Contents |
|---|---|
| SelfieCameraKit | Camera views, capture logic, preview components |
| RingLightKit | Ring light overlay, color presets, configuration |
| PremiumKit | Premium manager, gating utilities, paywall |
| SyncedSettingsKit | CloudSyncManager, settings model pattern |
Key Dependencies
| Dependency | Purpose | Integration |
|---|---|---|
| Bedrock | Design system, branding, cloud sync | Local Swift package |
| MijickCamera | Camera capture and preview | SPM dependency |
| RevenueCat | Subscription management | SPM dependency |
Code Quality Standards
- No magic numbers: All values from Design constants
- Full accessibility: Every interactive element has VoiceOver support
- Protocol-first: Shared behavior defined via protocols
- Separation of concerns: Views are dumb, ViewModels contain logic
- Modern APIs: Swift 6, async/await, @Observable
- Documentation: Code comments, README, implementation guides
Future Enhancements
Potential areas for expansion:
- Real-time filters (beauty, color grading)
- Gesture-based capture (smile detection)
- Widget for quick camera access
- Apple Watch remote trigger
- Export presets (aspect ratios, watermarks)
- Social sharing integrations
This architecture demonstrates production-quality SwiftUI development while delivering a polished, competitive user experience.