State Management
Relevant source files
The following files were used as context for generating this wiki page:
State management in the Writer application is built using SwiftUI's Observation framework. The architecture centers around a set of specialized "Store" classes that manage specific domains of the application, such as file system operations, user interface themes, and layout configurations. These stores are initialized at the app's entry point and injected into the view hierarchy using the SwiftUI environment mechanism.
The primary goal of this system is to maintain a distraction-free editing environment by handling background tasks like autosave, security-scoped file access, and real-time markdown synchronization between the editor and preview components.
Sources: CLAUDE.md:15-17, Writer/WriterApp.swift:13-17
Centralized Architecture
The application follows a modular state architecture where different concerns are separated into distinct observable objects. These objects are managed at the WriterApp level and passed down as environment objects.
This diagram illustrates the flow of state from the root App struct down to specialized UI components via the environment.
Sources: Writer/WriterApp.swift:13-20, Writer/WriterApp.swift:76-79
Core Store Components
| Component | Responsibility | Primary Data Structures |
|---|---|---|
| EditorStore | Manages file tree, document content, file operations (copy/paste/delete), and persistence. | FileNode, URL, String (documentText) |
| ThemeStore | Controls visual appearance of the preview and typography settings. | PreviewTheme |
| LayoutStore | Tracks UI state such as the visibility of the preview pane. | Bool (showPreview) |
Sources: CLAUDE.md:21-35, Writer/EditorStore.swift:17-45
File System & Document State
The EditorStore is the most complex state container, managing the interaction between the UI and the macOS file system. It uses FileNode to represent a hierarchical view of the workspace.
Security-Scoped Persistence
To maintain access to user-selected folders across app launches without repeated prompts, the system utilizes Security-Scoped Bookmarks.
The sequence of persisting and regaining access to the root writing directory.
Document Lifecycle & Autosave
The application manages document state through a combination of manual saves and an automated debounced task.
- Selection: When a file is selected,
selectFile(at:)loads the content intodocumentText. - Modification: UI changes to
documentTexttrigger anonChangemodifier inContentView. - Debouncing:
scheduleAutosave()cancels any existing task and creates a new one with a 350ms delay. - Persistence: If the task completes without cancellation,
persistCurrentDocument()writes the text to disk if it differs fromlastSavedText.
Sources: Writer/EditorStore.swift:316-339, Writer/ContentView.swift:42-44
UI and Theme State
Theme management allows for real-time updates to the preview rendering without affecting the raw markdown data.
Theme Synchronization
The ThemeStore holds the active PreviewTheme. When the user modifies settings in the ThemeEditorView, the ThemeStore updates, which in turn causes the WebView (via ContentView) to re-render the HTML with updated inline CSS.
The data flow for updating visual themes in the preview pane.
Sources: Writer/ThemeEditorView.swift:15-25, Writer/ContentView.swift:115-117, CLAUDE.md:25-27
Layout State
UI-specific state like the visibility of the preview pane is managed by LayoutStore. This is toggled via:
- Toolbar Button: An icon in the main window.
- Menu Command: "Show/Hide Preview" in the View menu.
- Keyboard Shortcut:
Command + Option + PorCommand + P.
Sources: Writer/WriterApp.swift:141-146, Writer/ContentView.swift:54-61
Conclusion
State management in Writer leverages the modern Swift Observation framework to create a reactive and decoupled architecture. By separating file system logic (EditorStore), visual styling (ThemeStore), and interface configuration (LayoutStore), the application ensures that complex operations like security-scoped file access and debounced autosaving remain transparent to the user, facilitating a "distraction-free" experience.