| 12 | import UniformTypeIdentifiers |
| 13 | |
| 14 | struct SettingsView: View { |
| 15 | private struct ShortcutRowContent { |
| 16 | let icon: String |
| 17 | let iconColor: Color |
| 18 | let title: String |
| 19 | let description: String |
| 20 | } |
| 21 | |
| 22 | @EnvironmentObject var appServices: AppServices |
| 23 | private var asr: ASRService { |
| 24 | self.appServices.asr |
| 25 | } |
| 26 | |
| 27 | @Environment(\.colorScheme) private var colorScheme |
| 28 | @Environment(\.theme) private var theme |
| 29 | @Environment(\.accessibilityReduceMotion) private var accessibilityReduceMotion |
| 30 | @ObservedObject private var settings = SettingsStore.shared |
| 31 | @ObservedObject var microphonePreferenceCoordinator: MicrophonePreferenceCoordinator |
| 32 | @Binding var appear: Bool |
| 33 | @Binding var visualizerNoiseThreshold: Double |
| 34 | @Binding var selectedInputUID: String |
| 35 | @Binding var selectedOutputUID: String |
| 36 | @Binding var inputDevices: [AudioDevice.Device] |
| 37 | @Binding var outputDevices: [AudioDevice.Device] |
| 38 | @Binding var accessibilityEnabled: Bool |
| 39 | @Binding var primaryDictationShortcuts: [HotkeyShortcut] |
| 40 | @Binding var activeShortcutRecordingTarget: ShortcutRecordingTarget? |
| 41 | @Binding var shortcutRecordingMessage: String? |
| 42 | @Binding var commandModeShortcut: HotkeyShortcut? |
| 43 | @Binding var rewriteShortcut: HotkeyShortcut |
| 44 | @Binding var cancelRecordingShortcut: HotkeyShortcut |
| 45 | @Binding var pasteLastTranscriptionShortcut: HotkeyShortcut? |
| 46 | @Binding var commandModeShortcutEnabled: Bool |
| 47 | @Binding var rewriteShortcutEnabled: Bool |
| 48 | @Binding var pasteLastTranscriptionShortcutEnabled: Bool |
| 49 | @Binding var hotkeyManagerInitialized: Bool |
| 50 | @Binding var hotkeyMode: HotkeyActivationMode |
| 51 | @Binding var enableStreamingPreview: Bool |
| 52 | @Binding var copyToClipboard: Bool |
| 53 | |
| 54 | // CRITICAL FIX: Cache default device names to avoid CoreAudio calls during view body evaluation. |
| 55 | // Querying AudioDevice.getDefaultInputDevice() in the view body triggers HALSystem::InitializeShell() |
| 56 | // which races with SwiftUI's AttributeGraph metadata processing and causes EXC_BAD_ACCESS crashes. |
| 57 | @State private var cachedDefaultInputUID: String = "" |
| 58 | @State private var cachedDefaultOutputName: String = "" |
| 59 | |
| 60 | // Analytics consent UI state (default ON; user can opt-out) |
| 61 | @State private var shareAnonymousAnalytics: Bool = SettingsStore.shared.shareAnonymousAnalytics |
| 62 | @State private var showAnalyticsPrivacy: Bool = false |
| 63 | @State private var pendingAnalyticsValue: Bool? = nil |
| 64 | @State private var showAreYouSureToStopAnalytics: Bool = false |
| 65 | @State private var rollbackVersion: String = "" |
| 66 | @State private var isRollingBack: Bool = false |
| 67 | @State private var audioHistoryBudgetText: String = Self.audioBudgetText(for: SettingsStore.shared.audioHistoryBudgetGB) |
| 68 | @State private var audioHistoryUsageBytes: Int64 = DictationAudioHistoryStore.shared.audioUsageBytes() |
| 69 | @State private var draggedMicrophoneUID: String? |
| 70 | @State private var hoveredMicrophoneUID: String? |
| 71 |
no test coverage detected