How to Access Application Settings in FluidVoice: Complete Guide to SettingsStore
FluidVoice stores all user-configurable data in a thread-safe singleton called SettingsStore that conforms to ObservableObject, allowing SwiftUI views to subscribe to changes via @ObservedObject while automatically persisting values to UserDefaults.
The FluidVoice repository organizes application preferences through a centralized architecture defined in Sources/Fluid/Persistence/SettingsStore.swift. This approach ensures that whether you are building a preference pane, reacting to hotkey changes, or configuring dictation prompts, you access application settings in FluidVoice through a single, consistent API backed by UserDefaults and KeychainService for sensitive data.
What is SettingsStore?
SettingsStore is the central nervous system for FluidVoice configuration. Implemented as a singleton accessible via SettingsStore.shared, this class conforms to ObservableObject and manages the persistence layer for all user preferences.
The store automatically handles serialization through UserDefaults (with KeychainService handling secrets), eliminates manual save calls, and broadcasts changes via objectWillChange.send() to trigger SwiftUI view updates. Located in Sources/Fluid/Persistence/SettingsStore.swift, it exposes typed properties and helper methods that provide type-safe access to raw preference values.
How to Access Application Settings in FluidVoice
Reading Settings
Access any setting by querying the computed property on the shared instance. The store provides typed accessors that abstract away the underlying UserDefaults keys.
import Fluid
// Access the transcription preview character limit
let limit = SettingsStore.shared.transcriptionPreviewCharLimit
// Retrieve the active dictation prompt for a specific slot
let selection = SettingsStore.shared.dictationPromptSelection(for: .primary)
// Check if launch at startup is enabled
let autoLaunch = SettingsStore.shared.launchAtStartupEnabled
Writing Settings
Assign values directly to properties; the store automatically persists changes and notifies observers. This pattern appears throughout Sources/Fluid/Views/CommandModeView.swift and other view files.
// Update the preview limit with bounds checking
let current = SettingsStore.shared.transcriptionPreviewCharLimit
let step = SettingsStore.transcriptionPreviewCharLimitStep
let max = SettingsStore.transcriptionPreviewCharLimitRange.upperBound
SettingsStore.shared.transcriptionPreviewCharLimit = min(current + step, max)
// Configure a hotkey for a specific prompt selection
var config = SettingsStore.shared.dictationPromptConfiguration(for: selection)
config.shortcut = newHotkey
SettingsStore.shared.setDictationPromptConfiguration(config, for: selection)
Observing Changes
Inject the store into SwiftUI views using @ObservedObject to ensure the UI reacts to preference mutations. This pattern is demonstrated in Sources/Fluid/fluidApp.swift where the top-level view maintains a reference to SettingsStore.shared.
import SwiftUI
struct PreviewLimitView: View {
@ObservedObject private var settings = SettingsStore.shared
var body: some View {
Text("Preview limit: \(settings.transcriptionPreviewCharLimit) characters")
.padding()
}
}
Common Settings and Properties
The following settings represent the most frequently accessed configuration options within the FluidVoice codebase:
-
transcriptionPreviewCharLimit– Controls the character limit for the transcription preview pane. Accessed inSources/Fluid/Views/NotchContentViews.swift. -
dictationPromptSelection(for:)– Returns the active prompt selection (default, profile, Private AI, or off) for a given shortcut slot. Used extensively inSources/Fluid/Views/CommandModeView.swift. -
selectedDictationPromptProfile– Identifies the currently chosen dictation prompt profile, if any. -
defaultPromptOverride(for:)– Retrieves optional user-provided overrides for built-in system prompts (e.g.,.dictatemode). -
launchAtStartupEnabled– Boolean indicating whether FluidVoice registers as a macOS login item. -
availableModelsByProvider– Dictionary of AI models organized by provider, accessed inSources/Fluid/Views/RewriteModeView.swiftto populate model selection interfaces.
Practical Code Examples
Observing Settings from a Service
For non-SwiftUI contexts such as background services, subscribe to the objectWillChange publisher to react to configuration updates.
import Combine
class PromptService {
private var cancellable: AnyCancellable?
init() {
cancellable = SettingsStore.shared.objectWillChange.sink { _ in
self.reloadPrompt()
}
}
private func reloadPrompt() {
let prompt = SettingsStore.shared.effectiveSystemPrompt(for: .dictate)
// Pass updated prompt to AI provider...
}
}
Determining Active Prompt Description
Handle the DictationPromptSelection enum to provide user-facing descriptions of the current configuration.
func activePromptDescription() -> String {
let selection = SettingsStore.shared.dictationPromptSelection(for: .primary)
switch selection {
case .off:
return "Dictation is turned off"
case .default:
return "Using the default system prompt"
case .privateAI:
return "Using Private AI prompt"
case .profile(let id):
return "Using custom profile \(id)"
}
}
Accessing Visualizer Settings
The NotchContentViews.swift file demonstrates accessing audio visualization thresholds.
// From Sources/Fluid/Views/NotchContentViews.swift
let noiseThreshold = SettingsStore.shared.visualizerNoiseThreshold
Summary
- FluidVoice centralizes all application settings in
SettingsStore, a thread-safe singleton defined inSources/Fluid/Persistence/SettingsStore.swift. - Access settings through
SettingsStore.sharedusing typed properties that abstractUserDefaultspersistence. - Observe changes by injecting the store as an
@ObservedObjectin SwiftUI views or subscribing toobjectWillChangein Combine-based services. - Modify values by direct assignment; the store automatically triggers persistence and UI updates without manual save calls.
- Secure sensitive data through internal
KeychainServiceintegration while standard preferences useUserDefaults.
Frequently Asked Questions
Where are FluidVoice settings physically stored?
Settings are persisted to UserDefaults standard storage, with sensitive credentials managed by the internal KeychainService class. You never need to call synchronize() or perform manual writes; the SettingsStore handles persistence automatically when you modify any property.
How do I observe settings changes in SwiftUI?
Inject SettingsStore.shared as an @ObservedObject in your view struct. Because the store conforms to ObservableObject and calls objectWillChange.send() on every mutation, any view containing @ObservedObject var settings = SettingsStore.shared will automatically redraw when settings change, as implemented in Sources/Fluid/fluidApp.swift.
Is SettingsStore thread-safe?
Yes. The singleton instance is designed to be accessed from any thread or queue safely. While SwiftUI mutations must occur on the main thread by architectural requirement, the underlying UserDefaults and KeychainService operations are thread-safe, allowing background services to read settings without race conditions.
How do I access settings from a non-SwiftUI context?
Use the Combine framework to subscribe to SettingsStore.shared.objectWillChange. This publisher emits whenever any setting changes, allowing services, view models, or background tasks to react to configuration updates without maintaining a direct view reference, as shown in the PromptService example above.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →