diff --git a/Facett.xcodeproj/project.pbxproj b/Facett.xcodeproj/project.pbxproj index 7b4dfbc..885ec79 100644 --- a/Facett.xcodeproj/project.pbxproj +++ b/Facett.xcodeproj/project.pbxproj @@ -419,10 +419,10 @@ GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Facett/Info.plist; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.photography"; - INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "Bluetooth is used to discover and connect to your GoPro cameras for remote control and settings management."; - INFOPLIST_KEY_NSBluetoothPeripheralUsageDescription = "Bluetooth is used to discover and connect to your GoPro cameras for remote control and settings management."; + INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "Bluetooth is used to discover and connect to your action cameras for remote control and settings management."; + INFOPLIST_KEY_NSBluetoothPeripheralUsageDescription = "Bluetooth is used to discover and connect to your action cameras for remote control and settings management."; INFOPLIST_KEY_NSMicrophoneUsageDescription = "Voice control allows you to start and stop recording by saying \"start\" or \"stop\"."; - INFOPLIST_KEY_NSSpeechRecognitionUsageDescription = "Speech recognition enables voice commands to control your GoPro cameras."; + INFOPLIST_KEY_NSSpeechRecognitionUsageDescription = "Speech recognition enables voice commands to control your cameras."; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -458,10 +458,10 @@ GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = Facett/Info.plist; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.photography"; - INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "Bluetooth is used to discover and connect to your GoPro cameras for remote control and settings management."; - INFOPLIST_KEY_NSBluetoothPeripheralUsageDescription = "Bluetooth is used to discover and connect to your GoPro cameras for remote control and settings management."; + INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "Bluetooth is used to discover and connect to your action cameras for remote control and settings management."; + INFOPLIST_KEY_NSBluetoothPeripheralUsageDescription = "Bluetooth is used to discover and connect to your action cameras for remote control and settings management."; INFOPLIST_KEY_NSMicrophoneUsageDescription = "Voice control allows you to start and stop recording by saying \"start\" or \"stop\"."; - INFOPLIST_KEY_NSSpeechRecognitionUsageDescription = "Speech recognition enables voice commands to control your GoPro cameras."; + INFOPLIST_KEY_NSSpeechRecognitionUsageDescription = "Speech recognition enables voice commands to control your cameras."; INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; diff --git a/Facett/AboutView.swift b/Facett/AboutView.swift new file mode 100644 index 0000000..510defe --- /dev/null +++ b/Facett/AboutView.swift @@ -0,0 +1,83 @@ +import SwiftUI + +struct AboutView: View { + @Environment(\.dismiss) private var dismiss + + private var appVersion: String { + let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0" + let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "1" + return "\(version) (\(build))" + } + + var body: some View { + NavigationView { + List { + Section { + VStack(spacing: 12) { + Image(systemName: "camera.on.rectangle.fill") + .font(.system(size: 48)) + .foregroundColor(.blue) + + Text("Facett") + .font(.title) + .fontWeight(.bold) + + Text("Version \(appVersion)") + .font(.subheadline) + .foregroundColor(.secondary) + } + .frame(maxWidth: .infinity) + .padding(.vertical, 16) + .listRowBackground(Color.clear) + } + + Section(header: Text("About")) { + Text("Facett is a multi-camera control app that connects to action cameras over Bluetooth Low Energy. Manage camera groups, synchronize settings, and start or stop recording across multiple cameras simultaneously.") + .font(.subheadline) + .foregroundColor(.secondary) + } + + Section(header: Text("Compatibility")) { + Label { + VStack(alignment: .leading, spacing: 4) { + Text("GoPro\u{00AE} HERO10 Black") + .font(.subheadline) + Text("Tested with GoPro Labs firmware. Other models may work but are not officially supported.") + .font(.caption) + .foregroundColor(.secondary) + } + } icon: { + Image(systemName: "checkmark.circle.fill") + .foregroundColor(.green) + } + + Label { + VStack(alignment: .leading, spacing: 4) { + Text("GoPro Labs Firmware Required") + .font(.subheadline) + Text("Install GoPro Labs firmware on your cameras for full BLE connectivity.") + .font(.caption) + .foregroundColor(.secondary) + } + } icon: { + Image(systemName: "exclamationmark.triangle.fill") + .foregroundColor(.orange) + } + } + + Section(header: Text("Legal")) { + Text("This product and/or service is not affiliated with, endorsed by or in any way associated with GoPro Inc. or its products and services. GoPro, HERO and their respective logos are trademarks or registered trademarks of GoPro, Inc.") + .font(.caption) + .foregroundColor(.secondary) + } + } + .navigationTitle("About") + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button("Done") { dismiss() } + } + } + } + } +} diff --git a/Facett/Assets.xcassets/AppIcon.appiconset/icon1024 1.png b/Facett/Assets.xcassets/AppIcon.appiconset/icon1024 1.png index 0d89835..f80c528 100644 Binary files a/Facett/Assets.xcassets/AppIcon.appiconset/icon1024 1.png and b/Facett/Assets.xcassets/AppIcon.appiconset/icon1024 1.png differ diff --git a/Facett/Assets.xcassets/AppIcon.appiconset/icon1024 2.png b/Facett/Assets.xcassets/AppIcon.appiconset/icon1024 2.png index 0d89835..f80c528 100644 Binary files a/Facett/Assets.xcassets/AppIcon.appiconset/icon1024 2.png and b/Facett/Assets.xcassets/AppIcon.appiconset/icon1024 2.png differ diff --git a/Facett/Assets.xcassets/AppIcon.appiconset/icon1024.png b/Facett/Assets.xcassets/AppIcon.appiconset/icon1024.png index 0d89835..f80c528 100644 Binary files a/Facett/Assets.xcassets/AppIcon.appiconset/icon1024.png and b/Facett/Assets.xcassets/AppIcon.appiconset/icon1024.png differ diff --git a/Facett/Assets.xcassets/LaunchImage.imageset/launch 1.png b/Facett/Assets.xcassets/LaunchImage.imageset/launch 1.png index bcd9404..6d0a9ba 100644 Binary files a/Facett/Assets.xcassets/LaunchImage.imageset/launch 1.png and b/Facett/Assets.xcassets/LaunchImage.imageset/launch 1.png differ diff --git a/Facett/Assets.xcassets/LaunchImage.imageset/launch 2.png b/Facett/Assets.xcassets/LaunchImage.imageset/launch 2.png index bcd9404..6d0a9ba 100644 Binary files a/Facett/Assets.xcassets/LaunchImage.imageset/launch 2.png and b/Facett/Assets.xcassets/LaunchImage.imageset/launch 2.png differ diff --git a/Facett/Assets.xcassets/LaunchImage.imageset/launch.png b/Facett/Assets.xcassets/LaunchImage.imageset/launch.png index bcd9404..6d0a9ba 100644 Binary files a/Facett/Assets.xcassets/LaunchImage.imageset/launch.png and b/Facett/Assets.xcassets/LaunchImage.imageset/launch.png differ diff --git a/Facett/ContentView.swift b/Facett/ContentView.swift index a7b771b..5a11900 100644 --- a/Facett/ContentView.swift +++ b/Facett/ContentView.swift @@ -14,6 +14,7 @@ struct ContentView: View { @State private var showingConfigManagement = false @State private var showingVoiceNotificationSettings = false @State private var showingBugReportForm = false + @State private var showingAbout = false @State private var autoSyncTimer: Timer? @State private var syncRotation: Double = 0 @State private var showModeMismatchModal = false @@ -268,7 +269,8 @@ struct ContentView: View { showingCameraGroupManagement: $showingCameraGroupManagement, showingConfigManagement: $showingConfigManagement, showingVoiceNotificationSettings: $showingVoiceNotificationSettings, - showingBugReportForm: $showingBugReportForm + showingBugReportForm: $showingBugReportForm, + showingAbout: $showingAbout ) // QR Code Section - Prominent placement @@ -303,6 +305,9 @@ struct ContentView: View { .sheet(isPresented: $showingBugReportForm) { BugReportView() } + .sheet(isPresented: $showingAbout) { + AboutView() + } .alert("Camera Mode Mismatch", isPresented: $showModeMismatchModal) { Button("OK") { showModeMismatchModal = false diff --git a/Facett/ManagementButtonsView.swift b/Facett/ManagementButtonsView.swift index d79b4dd..da82693 100644 --- a/Facett/ManagementButtonsView.swift +++ b/Facett/ManagementButtonsView.swift @@ -75,6 +75,7 @@ struct ManagementButtonsView: View { @Binding var showingConfigManagement: Bool @Binding var showingVoiceNotificationSettings: Bool @Binding var showingBugReportForm: Bool + @Binding var showingAbout: Bool var body: some View { VStack(spacing: 12) { @@ -113,6 +114,16 @@ struct ManagementButtonsView: View { action: { showingBugReportForm = true } ) } + + HStack(spacing: 12) { + ManagementButton( + title: "About", + subtitle: "Info & Legal", + icon: "info.circle.fill", + color: .gray, + action: { showingAbout = true } + ) + } } } } diff --git a/Facett/VoiceNotificationSettingsView.swift b/Facett/VoiceNotificationSettingsView.swift index a2bbb78..9eb933d 100644 --- a/Facett/VoiceNotificationSettingsView.swift +++ b/Facett/VoiceNotificationSettingsView.swift @@ -49,7 +49,7 @@ struct VoiceNotificationSettingsView: View { .disabled(!voiceNotificationManager.voiceNotificationsEnabled) Button("Test Camera Connected") { - voiceNotificationManager.notifyCameraConnected(cameraName: "GoPro Hero 11") + voiceNotificationManager.notifyCameraConnected(cameraName: "Camera 1") } .disabled(!voiceNotificationManager.voiceNotificationsEnabled) }