Compare commits

..

No commits in common. "f39739a601f4e4d90dfe9fc78e395e502205ac0c" and "84b565cbb56743d16f8c11ebb6f971b58eb8cd94" have entirely different histories.

14 changed files with 1089 additions and 864 deletions

1193
AGENTS.md

File diff suppressed because it is too large Load Diff

View File

@ -34,8 +34,6 @@
EA836ABF2F0ACE8A00077F87 /* SelfieCam.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SelfieCam.app; sourceTree = BUILT_PRODUCTS_DIR; }; EA836ABF2F0ACE8A00077F87 /* SelfieCam.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SelfieCam.app; sourceTree = BUILT_PRODUCTS_DIR; };
EA836ACC2F0ACE8B00077F87 /* SelfieCamTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SelfieCamTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; EA836ACC2F0ACE8B00077F87 /* SelfieCamTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SelfieCamTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
EA836AD62F0ACE8B00077F87 /* SelfieCamUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SelfieCamUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; EA836AD62F0ACE8B00077F87 /* SelfieCamUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SelfieCamUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
EACONFIG002 /* SelfieCam/Configuration/Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = SelfieCam/Configuration/Debug.xcconfig; sourceTree = SOURCE_ROOT; };
EACONFIG003 /* SelfieCam/Configuration/Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = SelfieCam/Configuration/Release.xcconfig; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFileSystemSynchronizedRootGroup section */
@ -92,7 +90,6 @@
EA836ACF2F0ACE8B00077F87 /* SelfieCamTests */, EA836ACF2F0ACE8B00077F87 /* SelfieCamTests */,
EA836AD92F0ACE8B00077F87 /* SelfieCamUITests */, EA836AD92F0ACE8B00077F87 /* SelfieCamUITests */,
EA836AC02F0ACE8A00077F87 /* Products */, EA836AC02F0ACE8A00077F87 /* Products */,
EADCDD7D2F12FFC6007991B3 /* Recovered References */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@ -106,15 +103,6 @@
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
EADCDD7D2F12FFC6007991B3 /* Recovered References */ = {
isa = PBXGroup;
children = (
EACONFIG002 /* SelfieCam/Configuration/Debug.xcconfig */,
EACONFIG003 /* SelfieCam/Configuration/Release.xcconfig */,
);
name = "Recovered References";
sourceTree = "<group>";
};
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
@ -304,7 +292,6 @@
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
EA836ADE2F0ACE8B00077F87 /* Debug */ = { EA836ADE2F0ACE8B00077F87 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = EACONFIG002 /* SelfieCam/Configuration/Debug.xcconfig */;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
@ -338,7 +325,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf; DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; DEVELOPMENT_TEAM = 6R7KLBPBLZ;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES;
@ -369,7 +356,6 @@
}; };
EA836ADF2F0ACE8B00077F87 /* Release */ = { EA836ADF2F0ACE8B00077F87 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = EACONFIG003 /* SelfieCam/Configuration/Release.xcconfig */;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
@ -403,7 +389,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; DEVELOPMENT_TEAM = 6R7KLBPBLZ;
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES;
@ -433,7 +419,7 @@
CODE_SIGN_ENTITLEMENTS = SelfieCam/SelfieCam.entitlements; CODE_SIGN_ENTITLEMENTS = SelfieCam/SelfieCam.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; DEVELOPMENT_TEAM = 6R7KLBPBLZ;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSCameraUsageDescription = "SelfieCam needs camera access to display your live selfie preview, apply real-time filters and ring light effects, capture high-quality photos, and enable advanced features like Center Stage auto-framing."; INFOPLIST_KEY_NSCameraUsageDescription = "SelfieCam needs camera access to display your live selfie preview, apply real-time filters and ring light effects, capture high-quality photos, and enable advanced features like Center Stage auto-framing.";
@ -441,8 +427,8 @@
INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "SelfieCam needs photo library access to automatically save your captured photos to your device, making them available in the Photos app and other compatible applications."; INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "SelfieCam needs photo library access to automatically save your captured photos to your device, making them available in the Photos app and other compatible applications.";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_BackgroundColor = LaunchBackground;
INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES;
"INFOPLIST_KEY_UILaunchScreen_BackgroundColorName" = "LaunchBackground";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 18.6; IPHONEOS_DEPLOYMENT_TARGET = 18.6;
@ -451,7 +437,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "$(APP_BUNDLE_IDENTIFIER)"; PRODUCT_BUNDLE_IDENTIFIER = com.mbrucedogs.SelfieCam;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
STRING_CATALOG_GENERATE_SYMBOLS = YES; STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_APPROACHABLE_CONCURRENCY = YES;
@ -471,7 +457,7 @@
CODE_SIGN_ENTITLEMENTS = SelfieCam/SelfieCam.entitlements; CODE_SIGN_ENTITLEMENTS = SelfieCam/SelfieCam.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; DEVELOPMENT_TEAM = 6R7KLBPBLZ;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSCameraUsageDescription = "SelfieCam needs camera access to display your live selfie preview, apply real-time filters and ring light effects, capture high-quality photos, and enable advanced features like Center Stage auto-framing."; INFOPLIST_KEY_NSCameraUsageDescription = "SelfieCam needs camera access to display your live selfie preview, apply real-time filters and ring light effects, capture high-quality photos, and enable advanced features like Center Stage auto-framing.";
@ -479,8 +465,8 @@
INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "SelfieCam needs photo library access to automatically save your captured photos to your device, making them available in the Photos app and other compatible applications."; INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "SelfieCam needs photo library access to automatically save your captured photos to your device, making them available in the Photos app and other compatible applications.";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_BackgroundColor = LaunchBackground;
INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES;
"INFOPLIST_KEY_UILaunchScreen_BackgroundColorName" = "LaunchBackground";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 18.6; IPHONEOS_DEPLOYMENT_TARGET = 18.6;
@ -489,7 +475,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "$(APP_BUNDLE_IDENTIFIER)"; PRODUCT_BUNDLE_IDENTIFIER = com.mbrucedogs.SelfieCam;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
STRING_CATALOG_GENERATE_SYMBOLS = YES; STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_APPROACHABLE_CONCURRENCY = YES;
@ -507,11 +493,11 @@
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; DEVELOPMENT_TEAM = 6R7KLBPBLZ;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 26.0; IPHONEOS_DEPLOYMENT_TARGET = 26.0;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "$(TESTS_BUNDLE_IDENTIFIER)"; PRODUCT_BUNDLE_IDENTIFIER = com.mbrucedogs.SelfieCamTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
STRING_CATALOG_GENERATE_SYMBOLS = NO; STRING_CATALOG_GENERATE_SYMBOLS = NO;
SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_APPROACHABLE_CONCURRENCY = YES;
@ -529,11 +515,11 @@
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; DEVELOPMENT_TEAM = 6R7KLBPBLZ;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 26.0; IPHONEOS_DEPLOYMENT_TARGET = 26.0;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "$(TESTS_BUNDLE_IDENTIFIER)"; PRODUCT_BUNDLE_IDENTIFIER = com.mbrucedogs.SelfieCamTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
STRING_CATALOG_GENERATE_SYMBOLS = NO; STRING_CATALOG_GENERATE_SYMBOLS = NO;
SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_APPROACHABLE_CONCURRENCY = YES;
@ -550,10 +536,10 @@
buildSettings = { buildSettings = {
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; DEVELOPMENT_TEAM = 6R7KLBPBLZ;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "$(UITESTS_BUNDLE_IDENTIFIER)"; PRODUCT_BUNDLE_IDENTIFIER = com.mbrucedogs.SelfieCamUITests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
STRING_CATALOG_GENERATE_SYMBOLS = NO; STRING_CATALOG_GENERATE_SYMBOLS = NO;
SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_APPROACHABLE_CONCURRENCY = YES;
@ -570,10 +556,10 @@
buildSettings = { buildSettings = {
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; DEVELOPMENT_TEAM = 6R7KLBPBLZ;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "$(UITESTS_BUNDLE_IDENTIFIER)"; PRODUCT_BUNDLE_IDENTIFIER = com.mbrucedogs.SelfieCamUITests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
STRING_CATALOG_GENERATE_SYMBOLS = NO; STRING_CATALOG_GENERATE_SYMBOLS = NO;
SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_APPROACHABLE_CONCURRENCY = YES;

View File

@ -7,7 +7,7 @@
<key>SelfieCam.xcscheme_^#shared#^_</key> <key>SelfieCam.xcscheme_^#shared#^_</key>
<dict> <dict>
<key>orderHint</key> <key>orderHint</key>
<integer>0</integer> <integer>4</integer>
</dict> </dict>
</dict> </dict>
<key>SuppressBuildableAutocreation</key> <key>SuppressBuildableAutocreation</key>

View File

@ -1,18 +0,0 @@
// Base.xcconfig - Source of truth for all identifiers
// MIGRATION: Update COMPANY_IDENTIFIER and DEVELOPMENT_TEAM below
// =============================================================================
// COMPANY IDENTIFIER - CHANGE THIS FOR MIGRATION
// =============================================================================
COMPANY_IDENTIFIER = com.mbrucedogs
APP_NAME = SelfieCam
DEVELOPMENT_TEAM = 6R7KLBPBLZ
// =============================================================================
// DERIVED IDENTIFIERS - DO NOT EDIT
// =============================================================================
APP_BUNDLE_IDENTIFIER = $(COMPANY_IDENTIFIER).$(APP_NAME)
TESTS_BUNDLE_IDENTIFIER = $(COMPANY_IDENTIFIER).$(APP_NAME)Tests
UITESTS_BUNDLE_IDENTIFIER = $(COMPANY_IDENTIFIER).$(APP_NAME)UITests

View File

@ -1,7 +1,6 @@
// Debug.xcconfig // Debug.xcconfig
// Configuration for Debug builds // Configuration for Debug builds
#include "Base.xcconfig"
#include? "Secrets.xcconfig" #include? "Secrets.xcconfig"
// If Secrets.xcconfig doesn't exist (CI/CD), fall back to empty values // If Secrets.xcconfig doesn't exist (CI/CD), fall back to empty values

View File

@ -1,7 +1,6 @@
// Release.xcconfig // Release.xcconfig
// Configuration for Release builds // Configuration for Release builds
#include "Base.xcconfig"
#include? "Secrets.xcconfig" #include? "Secrets.xcconfig"
// If Secrets.xcconfig doesn't exist (CI/CD), fall back to empty values // If Secrets.xcconfig doesn't exist (CI/CD), fall back to empty values

View File

@ -0,0 +1,71 @@
//
// ColorPickerOverlay.swift
// SelfieCam
//
// Created by Matt Bruce on 1/4/26.
//
import SwiftUI
import Bedrock
// MARK: - Color Picker Overlay
struct ColorPickerOverlay: View {
@Binding var selectedColor: Color
@Binding var isPresented: Bool
private let colors: [Color] = [
.white, .red, .orange, .yellow, .green, .blue, .purple, .pink,
.gray, .black, Color(red: 1.0, green: 0.5, blue: 0.0), // Coral
Color(red: 0.5, green: 1.0, blue: 0.5), // Mint
Color(red: 0.5, green: 0.5, blue: 1.0), // Periwinkle
Color(red: 1.0, green: 0.5, blue: 1.0), // Magenta
]
var body: some View {
ZStack {
// Semi-transparent background
Color.black.opacity(Design.Opacity.medium)
.ignoresSafeArea()
// Color picker content
VStack(spacing: Design.Spacing.medium) {
// Header
Text("Ring Light Color")
.font(.system(size: 18, weight: .semibold))
.foregroundStyle(Color.white)
// Color grid
LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 4), spacing: Design.Spacing.small) {
ForEach(colors, id: \.self) { color in
Circle()
.fill(color)
.frame(width: 50, height: 50)
.overlay(
Circle()
.stroke(Color.white.opacity(selectedColor == color ? 1.0 : 0.3), lineWidth: selectedColor == color ? 3 : 1)
)
.onTapGesture {
selectedColor = color
isPresented = false
}
}
}
// Done button
Button("Done") {
isPresented = false
}
.font(.system(size: 16, weight: .medium))
.foregroundStyle(Color.white)
.padding(.vertical, Design.Spacing.small)
}
.padding(Design.Spacing.large)
.background(
RoundedRectangle(cornerRadius: Design.CornerRadius.large)
.fill(Color.black.opacity(Design.Opacity.strong))
)
.padding(.horizontal, Design.Spacing.large)
}
}
}

View File

@ -0,0 +1,254 @@
//
// ExpandableControlsPanel.swift
// CameraTester
//
// Created by Matt Bruce on 1/2/26.
//
import SwiftUI
import Bedrock
import MijickCamera
// MARK: - Expandable Controls Panel
struct ExpandableControlsPanel: View {
@Binding var isExpanded: Bool
// Collapsed state info
let hasActiveSettings: Bool
let activeSettingsIcons: [String]
// Control properties
let flashMode: CameraFlashMode
let flashIcon: String
let onFlashTap: () -> Void
let isFlashSyncedWithRingLight: Bool
let onFlashSyncTap: () -> Void
let hdrMode: CameraHDRMode
let hdrIcon: String
let onHDRTap: () -> Void
let isGridVisible: Bool
let gridIcon: String
let onGridTap: () -> Void
let photoQuality: PhotoQuality
let onQualityTap: () -> Void
let isCenterStageAvailable: Bool
let isCenterStageEnabled: Bool
let onCenterStageTap: () -> Void
let isFrontCamera: Bool
let onFlipCameraTap: () -> Void
let isRingLightEnabled: Bool
let onRingLightTap: () -> Void
let ringLightColor: Color
let onRingLightColorTap: () -> Void
let ringLightSize: CGFloat
let onRingLightSizeTap: () -> Void
let ringLightOpacity: Double
let onRingLightOpacityTap: () -> Void
// Layout constants
private let collapsedHeight: CGFloat = 36
private let iconSize: CGFloat = 16
private let maxVisibleIcons: Int = 3
// Grid layout
private let columns = [
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible())
]
var body: some View {
VStack(spacing: 0) {
// Header row (always visible) - acts as the collapsed pill
Button(action: { isExpanded.toggle() }) {
HStack(spacing: Design.Spacing.small) {
// Chevron that rotates
Image(systemName: "chevron.down")
.font(.system(size: iconSize, weight: .semibold))
.foregroundStyle(Color.white)
.rotationEffect(.degrees(isExpanded ? 180 : 0))
// Show active setting icons when collapsed
if !isExpanded && hasActiveSettings {
HStack(spacing: Design.Spacing.xSmall) {
ForEach(activeSettingsIcons.prefix(maxVisibleIcons), id: \.self) { icon in
Image(systemName: icon)
.font(.system(size: iconSize, weight: .medium))
.foregroundStyle(Color.yellow)
}
}
}
if isExpanded {
Spacer()
}
}
.frame(height: collapsedHeight)
.frame(maxWidth: isExpanded ? .infinity : nil)
.padding(.horizontal, Design.Spacing.medium)
}
.accessibilityLabel("Camera controls")
.accessibilityHint(isExpanded ? "Tap to collapse settings" : "Tap to expand camera settings")
// Expandable content
if isExpanded {
ScrollView {
VStack(spacing: Design.Spacing.large) {
// Camera Controls Section
VStack(spacing: Design.Spacing.medium) {
// Section header
Text("Camera Controls")
.font(.system(size: 14, weight: .semibold))
.foregroundStyle(Color.white.opacity(0.8))
.frame(maxWidth: .infinity, alignment: .leading)
// Controls grid
LazyVGrid(columns: columns, spacing: Design.Spacing.medium) {
// Flash
ExpandedControlItem(
icon: flashIcon,
label: flashLabel,
isActive: flashMode != .off,
action: onFlashTap
)
// Flash Sync
ExpandedControlItem(
icon: isFlashSyncedWithRingLight ? "link" : "link.slash",
label: "SYNC",
isActive: isFlashSyncedWithRingLight,
action: onFlashSyncTap
)
// HDR
ExpandedControlItem(
icon: hdrIcon,
label: hdrLabel,
isActive: hdrMode != .off,
action: onHDRTap
)
// Grid
ExpandedControlItem(
icon: gridIcon,
label: "GRID",
isActive: isGridVisible,
action: onGridTap
)
// Quality
ExpandedControlItem(
icon: photoQuality.icon,
label: photoQuality.rawValue.uppercased(),
isActive: false,
action: onQualityTap
)
// Center Stage (if available)
if isCenterStageAvailable {
ExpandedControlItem(
icon: isCenterStageEnabled ? "person.crop.rectangle.fill" : "person.crop.rectangle",
label: "STAGE",
isActive: isCenterStageEnabled,
action: onCenterStageTap
)
}
// Flip Camera
ExpandedControlItem(
icon: "arrow.triangle.2.circlepath.camera",
label: isFrontCamera ? "FRONT" : "BACK",
isActive: false,
action: onFlipCameraTap
)
}
}
// Ring Light Section
VStack(spacing: Design.Spacing.medium) {
// Section header
Text("Ring Light")
.font(.system(size: 14, weight: .semibold))
.foregroundStyle(Color.white.opacity(0.8))
.frame(maxWidth: .infinity, alignment: .leading)
// Ring light controls grid
LazyVGrid(columns: columns, spacing: Design.Spacing.medium) {
// Ring Light Enable/Disable
ExpandedControlItem(
icon: isRingLightEnabled ? "circle.fill" : "circle",
label: "ENABLE",
isActive: isRingLightEnabled,
action: onRingLightTap
)
// Ring Color
ExpandedControlItem(
icon: "circle.fill",
label: "COLOR",
isActive: false,
action: onRingLightColorTap
)
.foregroundStyle(ringLightColor)
// Ring Size
ExpandedControlItem(
icon: "circle",
label: "SIZE",
isActive: false,
action: onRingLightSizeTap
)
// Ring Brightness
ExpandedControlItem(
icon: "circle.fill",
label: "BRIGHT",
isActive: false,
action: onRingLightOpacityTap
)
.foregroundStyle(Color.white.opacity(ringLightOpacity))
}
}
}
.padding(.top, Design.Spacing.small)
.padding(.bottom, Design.Spacing.medium)
.padding(.horizontal, Design.Spacing.small)
}
.frame(maxHeight: 400) // Limit max height to prevent excessive scrolling
.scrollIndicators(.hidden) // Hide scroll indicators for cleaner look
}
}
.padding(.horizontal, Design.Spacing.small)
.background(
RoundedRectangle(cornerRadius: isExpanded ? Design.CornerRadius.large : collapsedHeight / 2)
.fill(Color.black.opacity(isExpanded ? Design.Opacity.strong : Design.Opacity.medium))
)
.animation(.easeInOut(duration: 0.25), value: isExpanded)
}
private var flashLabel: String {
switch flashMode {
case .off: return "FLASH"
case .auto: return "AUTO"
case .on: return "ON"
}
}
private var hdrLabel: String {
switch hdrMode {
case .off: return "HDR"
case .auto: return "AUTO"
case .on: return "ON"
}
}
}

View File

@ -0,0 +1,45 @@
//
// ExpandedControlItem.swift
// CameraTester
//
// Created by Matt Bruce on 1/2/26.
//
import SwiftUI
import Bedrock
// MARK: - Expanded Control Item
struct ExpandedControlItem: View {
let icon: String
let label: String
let isActive: Bool
let action: () -> Void
// Layout constants
private let iconSize: CGFloat = 28
private let buttonSize: CGFloat = 56
private let labelFontSize: CGFloat = 10
var body: some View {
Button(action: action) {
VStack(spacing: Design.Spacing.xSmall) {
ZStack {
Circle()
.fill(isActive ? Color.yellow : Color.black.opacity(Design.Opacity.light))
.frame(width: buttonSize, height: buttonSize)
Image(systemName: icon)
.font(.system(size: iconSize, weight: .medium))
.foregroundStyle(isActive ? Color.black : Color.white)
}
Text(label)
.font(.system(size: labelFontSize, weight: .medium))
.foregroundStyle(isActive ? Color.yellow : Color.white)
}
}
.accessibilityLabel("\(label)")
.accessibilityValue(isActive ? "On" : "Off")
}
}

View File

@ -0,0 +1,72 @@
//
// OpacitySliderOverlay.swift
// SelfieCam
//
// Created by Matt Bruce on 1/4/26.
//
import SwiftUI
import Bedrock
// MARK: - Opacity Slider Overlay
struct OpacitySliderOverlay: View {
@Binding var selectedOpacity: Double
@Binding var isPresented: Bool
private let minOpacity: Double = 0.1
private let maxOpacity: Double = 1.0
var body: some View {
ZStack {
// Semi-transparent background
Color.black.opacity(Design.Opacity.medium)
.ignoresSafeArea()
// Opacity slider content
VStack(spacing: Design.Spacing.medium) {
// Header
Text("Ring Light Brightness")
.font(.system(size: 18, weight: .semibold))
.foregroundStyle(Color.white)
// Current opacity display as percentage
Text("\(Int(selectedOpacity * 100))%")
.font(.system(size: 24, weight: .bold))
.foregroundStyle(Color.white)
.frame(width: 80)
// Slider
Slider(value: $selectedOpacity, in: minOpacity...maxOpacity, step: 0.05)
.tint(Color.white)
.padding(.horizontal, Design.Spacing.medium)
// Opacity range labels
HStack {
Text("10%")
.font(.system(size: 14))
.foregroundStyle(Color.white.opacity(0.7))
Spacer()
Text("100%")
.font(.system(size: 14))
.foregroundStyle(Color.white.opacity(0.7))
}
.padding(.horizontal, Design.Spacing.medium)
// Done button
Button("Done") {
isPresented = false
}
.font(.system(size: 16, weight: .medium))
.foregroundStyle(Color.white)
.padding(.vertical, Design.Spacing.small)
}
.padding(Design.Spacing.large)
.background(
RoundedRectangle(cornerRadius: Design.CornerRadius.large)
.fill(Color.black.opacity(Design.Opacity.strong))
)
.padding(.horizontal, Design.Spacing.large)
}
}
}

View File

@ -0,0 +1,72 @@
//
// SizeSliderOverlay.swift
// SelfieCam
//
// Created by Matt Bruce on 1/4/26.
//
import SwiftUI
import Bedrock
// MARK: - Size Slider Overlay
struct SizeSliderOverlay: View {
@Binding var selectedSize: CGFloat
@Binding var isPresented: Bool
private let minSize: CGFloat = SettingsViewModel.minRingSize
private let maxSize: CGFloat = SettingsViewModel.maxRingSize
var body: some View {
ZStack {
// Semi-transparent background
Color.black.opacity(Design.Opacity.medium)
.ignoresSafeArea()
// Size slider content
VStack(spacing: Design.Spacing.medium) {
// Header
Text("Ring Light Size")
.font(.system(size: 18, weight: .semibold))
.foregroundStyle(Color.white)
// Current size display
Text("\(Int(selectedSize))")
.font(.system(size: 24, weight: .bold))
.foregroundStyle(Color.white)
.frame(width: 60)
// Slider
Slider(value: $selectedSize, in: minSize...maxSize, step: 5)
.tint(Color.white)
.padding(.horizontal, Design.Spacing.medium)
// Size range labels
HStack {
Text("\(Int(minSize))")
.font(.system(size: 14))
.foregroundStyle(Color.white.opacity(0.7))
Spacer()
Text("\(Int(maxSize))")
.font(.system(size: 14))
.foregroundStyle(Color.white.opacity(0.7))
}
.padding(.horizontal, Design.Spacing.medium)
// Done button
Button("Done") {
isPresented = false
}
.font(.system(size: 16, weight: .medium))
.foregroundStyle(Color.white)
.padding(.vertical, Design.Spacing.small)
}
.padding(Design.Spacing.large)
.background(
RoundedRectangle(cornerRadius: Design.CornerRadius.large)
.fill(Color.black.opacity(Design.Opacity.strong))
)
.padding(.horizontal, Design.Spacing.large)
}
}
}

View File

@ -31,10 +31,6 @@ struct ContentView: View {
var body: some View { var body: some View {
ZStack { ZStack {
// Background matching launch screen to prevent black flash during camera init
Color.Branding.primary
.ignoresSafeArea()
// Camera view - wrapped in EquatableView to prevent re-evaluation on settings changes // Camera view - wrapped in EquatableView to prevent re-evaluation on settings changes
if !showPhotoReview { if !showPhotoReview {
EquatableView(content: CameraContainerView( EquatableView(content: CameraContainerView(

View File

@ -11,24 +11,6 @@
} }
}, },
"idiom" : "universal" "idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.450",
"green" : "0.250",
"red" : "0.850"
}
},
"idiom" : "universal"
} }
], ],
"info" : { "info" : {

View File

@ -3,7 +3,6 @@
"strings" : { "strings" : {
"%@" : { "%@" : {
"comment" : "A button with an icon and label. The argument is the text to display in the button.", "comment" : "A button with an icon and label. The argument is the text to display in the button.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
@ -100,7 +99,6 @@
}, },
"%lld%%" : { "%lld%%" : {
"comment" : "A text label displaying the current brightness setting of the ring light, formatted as a percentage. The argument is the current brightness setting of the ring light, as a decimal between 0.0 and 1.", "comment" : "A text label displaying the current brightness setting of the ring light, formatted as a percentage. The argument is the current brightness setting of the ring light, as a decimal between 0.0 and 1.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
@ -198,7 +196,6 @@
}, },
"10%" : { "10%" : {
"comment" : "A label displayed alongside the left edge of the opacity slider.", "comment" : "A label displayed alongside the left edge of the opacity slider.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
@ -247,7 +244,6 @@
}, },
"100%" : { "100%" : {
"comment" : "A label displayed alongside the right edge of the opacity slider.", "comment" : "A label displayed alongside the right edge of the opacity slider.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
@ -560,7 +556,6 @@
} }
}, },
"Camera controls" : { "Camera controls" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
"stringUnit" : { "stringUnit" : {
@ -583,7 +578,6 @@
} }
}, },
"Camera Controls" : { "Camera Controls" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
"stringUnit" : { "stringUnit" : {
@ -775,51 +769,11 @@
}, },
"Choose the color of the ring light around the camera preview" : { "Choose the color of the ring light around the camera preview" : {
"comment" : "A description under the title of the light color preset section, explaining its purpose.", "comment" : "A description under the title of the light color preset section, explaining its purpose.",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true
"localizations" : {
"es-MX" : {
"stringUnit" : {
"state" : "translated",
"value" : "Elige el color del aro de luz alrededor de la vista previa de la cámara"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Choisissez la couleur de l'anneau lumineux autour de l'aperçu de la caméra"
}
},
"fr-CA" : {
"stringUnit" : {
"state" : "translated",
"value" : "Choisissez la couleur de l'anneau lumineux autour de l'aperçu de la caméra"
}
}
}
}, },
"Close" : { "Close" : {
"comment" : "A button label that closes the view.", "comment" : "A button label that closes the view.",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true
"localizations" : {
"es-MX" : {
"stringUnit" : {
"state" : "translated",
"value" : "Cerrar"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Fermer"
}
},
"fr-CA" : {
"stringUnit" : {
"state" : "translated",
"value" : "Fermer"
}
}
}
}, },
"Close preview" : { "Close preview" : {
"comment" : "A button label that closes the preview screen.", "comment" : "A button label that closes the preview screen.",
@ -1064,7 +1018,6 @@
}, },
"Enable Center Stage" : { "Enable Center Stage" : {
"comment" : "An accessibility label for the toggle that enables the \"Center Stage\" feature.", "comment" : "An accessibility label for the toggle that enables the \"Center Stage\" feature.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
@ -1570,7 +1523,6 @@
} }
}, },
"Last synced %@" : { "Last synced %@" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
"stringUnit" : { "stringUnit" : {
@ -1666,7 +1618,6 @@
}, },
"On" : { "On" : {
"comment" : "A value that describes a control item as \"On\".", "comment" : "A value that describes a control item as \"On\".",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
@ -2003,30 +1954,9 @@
}, },
"Retake photo" : { "Retake photo" : {
"comment" : "A button that, when tapped, allows the user to retake a photo.", "comment" : "A button that, when tapped, allows the user to retake a photo.",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true
"localizations" : {
"es-MX" : {
"stringUnit" : {
"state" : "translated",
"value" : "Tomar otra foto"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Reprendre la photo"
}
},
"fr-CA" : {
"stringUnit" : {
"state" : "translated",
"value" : "Reprendre la photo"
}
}
}
}, },
"Ring Light" : { "Ring Light" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
"stringUnit" : { "stringUnit" : {
@ -2098,7 +2028,6 @@
}, },
"Ring Light Color" : { "Ring Light Color" : {
"comment" : "The title of the color picker overlay.", "comment" : "The title of the color picker overlay.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
@ -2123,7 +2052,6 @@
}, },
"Ring Light Size" : { "Ring Light Size" : {
"comment" : "The title of the slider that allows the user to select the size of their ring light.", "comment" : "The title of the slider that allows the user to select the size of their ring light.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
@ -2221,27 +2149,7 @@
}, },
"Save photo" : { "Save photo" : {
"comment" : "A button that saves the currently displayed photo to the user's library.", "comment" : "A button that saves the currently displayed photo to the user's library.",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true
"localizations" : {
"es-MX" : {
"stringUnit" : {
"state" : "translated",
"value" : "Guardar foto"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Enregistrer la photo"
}
},
"fr-CA" : {
"stringUnit" : {
"state" : "translated",
"value" : "Enregistrer la photo"
}
}
}
}, },
"Saved to Photos" : { "Saved to Photos" : {
"comment" : "Text shown as a toast message when a photo is successfully saved to Photos.", "comment" : "Text shown as a toast message when a photo is successfully saved to Photos.",
@ -2270,27 +2178,7 @@
}, },
"Saves the photo to your library" : { "Saves the photo to your library" : {
"comment" : "An accessibility hint for the save button in the photo review view.", "comment" : "An accessibility hint for the save button in the photo review view.",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true
"localizations" : {
"es-MX" : {
"stringUnit" : {
"state" : "translated",
"value" : "Guarda la foto en tu biblioteca"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Enregistre la photo dans votre photothèque"
}
},
"fr-CA" : {
"stringUnit" : {
"state" : "translated",
"value" : "Enregistre la photo dans votre photothèque"
}
}
}
}, },
"Saving..." : { "Saving..." : {
"comment" : "A text that appears while a photo is being saved.", "comment" : "A text that appears while a photo is being saved.",
@ -2511,27 +2399,7 @@
}, },
"Share photo" : { "Share photo" : {
"comment" : "An accessibility label for the share button.", "comment" : "An accessibility label for the share button.",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true
"localizations" : {
"es-MX" : {
"stringUnit" : {
"state" : "translated",
"value" : "Compartir foto"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Partager la photo"
}
},
"fr-CA" : {
"stringUnit" : {
"state" : "translated",
"value" : "Partager la photo"
}
}
}
}, },
"Show colored light ring around camera preview" : { "Show colored light ring around camera preview" : {
"comment" : "Subtitle for the \"Enable Ring Light\" toggle in the Settings view.", "comment" : "Subtitle for the \"Enable Ring Light\" toggle in the Settings view.",
@ -2631,7 +2499,6 @@
}, },
"Sign in to iCloud to enable sync" : { "Sign in to iCloud to enable sync" : {
"comment" : "Subtitle of the iCloud sync section when the user is not signed into iCloud.", "comment" : "Subtitle of the iCloud sync section when the user is not signed into iCloud.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
@ -2732,7 +2599,7 @@
"localizations" : { "localizations" : {
"en" : { "en" : {
"stringUnit" : { "stringUnit" : {
"state" : "translated", "state" : "new",
"value" : "Subscribe to %1$@ for %2$@" "value" : "Subscribe to %1$@ for %2$@"
} }
}, },
@ -2758,7 +2625,6 @@
}, },
"Sync Now" : { "Sync Now" : {
"comment" : "A button label that triggers a sync action.", "comment" : "A button label that triggers a sync action.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
@ -2783,7 +2649,6 @@
}, },
"Sync Settings" : { "Sync Settings" : {
"comment" : "Title of a toggle that allows the user to enable or disable iCloud sync settings.", "comment" : "Title of a toggle that allows the user to enable or disable iCloud sync settings.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
@ -2808,7 +2673,6 @@
}, },
"Sync settings across all your devices" : { "Sync settings across all your devices" : {
"comment" : "Subtitle of the \"Sync Settings\" toggle in the Settings view, describing the functionality when sync is enabled.", "comment" : "Subtitle of the \"Sync Settings\" toggle in the Settings view, describing the functionality when sync is enabled.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
@ -2833,7 +2697,6 @@
}, },
"Synced" : { "Synced" : {
"comment" : "Text displayed in the iCloud sync section when the user's settings have been successfully synced.", "comment" : "Text displayed in the iCloud sync section when the user's settings have been successfully synced.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
@ -2857,7 +2720,6 @@
} }
}, },
"Syncing..." : { "Syncing..." : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
"stringUnit" : { "stringUnit" : {
@ -2905,7 +2767,6 @@
}, },
"Syncs settings across all your devices via iCloud" : { "Syncs settings across all your devices via iCloud" : {
"comment" : "An accessibility hint describing the functionality of the sync toggle in the settings view.", "comment" : "An accessibility hint describing the functionality of the sync toggle in the settings view.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
@ -2953,7 +2814,6 @@
} }
}, },
"Tap to collapse settings" : { "Tap to collapse settings" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
"stringUnit" : { "stringUnit" : {
@ -2976,7 +2836,6 @@
} }
}, },
"Tap to expand camera settings" : { "Tap to expand camera settings" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
"stringUnit" : { "stringUnit" : {
@ -3243,7 +3102,6 @@
}, },
"View on GitHub" : { "View on GitHub" : {
"comment" : "A button label that says \"View on GitHub\".", "comment" : "A button label that says \"View on GitHub\".",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {