Refactor persistence to combine document handling and workspace layout (#4031)

* Unify editor state persistence

* Review

* Fix

* Remove redundant DocumentDetails

* LoadDocumentContent indirection
This commit is contained in:
Timon
2026-04-19 11:31:21 +02:00
committed by GitHub
parent 2a2a60883d
commit 6c5e3c97f8
36 changed files with 562 additions and 699 deletions

View File

@@ -49,41 +49,18 @@ pub(super) fn handle_desktop_wrapper_message(dispatcher: &mut DesktopWrapperMess
let message = FrontendMessage::UpdateFullscreen { fullscreen };
dispatcher.queue_editor_message(message);
}
DesktopWrapperMessage::LoadDocument {
id,
document,
to_front,
select_after_open,
} => {
let message = PortfolioMessage::OpenDocumentFileWithId {
document_id: id,
document_name: Some(document.name),
document_path: document.path,
document_serialized_content: document.content,
document_is_auto_saved: true,
document_is_saved: document.is_saved,
to_front,
select_after_open,
};
DesktopWrapperMessage::LoadDocumentContent { id, document } => {
let message = PersistentStateMessage::LoadDocument { document_id: id, document };
dispatcher.queue_editor_message(message);
}
DesktopWrapperMessage::SelectDocument { id } => {
let message = PortfolioMessage::SelectDocument { document_id: id };
DesktopWrapperMessage::LoadPersistedState { state } => {
let message = PersistentStateMessage::LoadState { state };
dispatcher.queue_editor_message(message);
}
DesktopWrapperMessage::LoadPreferences { preferences } => {
let message = PreferencesMessage::Load { preferences };
dispatcher.queue_editor_message(message);
}
DesktopWrapperMessage::LoadWorkspaceLayout { workspace_layout } => match ron::from_str(&workspace_layout) {
Ok(layout) => {
let message = PortfolioMessage::LoadWorkspaceLayout { layout };
dispatcher.queue_editor_message(message);
}
Err(e) => {
tracing::error!("Failed to deserialize workspace layout: {e}");
}
},
#[cfg(target_os = "macos")]
DesktopWrapperMessage::MenuEvent { id } => {
if let Some(message) = crate::utils::menu::parse_item_path(id) {

View File

@@ -3,7 +3,7 @@ use graphite_editor::messages::layout::utility_types::layout_widget::LayoutTarge
use graphite_editor::messages::prelude::FrontendMessage;
use super::DesktopWrapperMessageDispatcher;
use super::messages::{DesktopFrontendMessage, Document, FileFilter, OpenFileDialogContext, SaveFileDialogContext};
use super::messages::{DesktopFrontendMessage, FileFilter, OpenFileDialogContext, SaveFileDialogContext};
pub(super) fn intercept_frontend_message(dispatcher: &mut DesktopWrapperMessageDispatcher, message: FrontendMessage) -> Option<FrontendMessage> {
match message {
@@ -67,36 +67,23 @@ pub(super) fn intercept_frontend_message(dispatcher: &mut DesktopWrapperMessageD
dispatcher.respond(DesktopFrontendMessage::UpdateUIScale { scale });
return Some(FrontendMessage::UpdateUIScale { scale });
}
FrontendMessage::TriggerPersistenceWriteDocument { document_id, document, details } => {
dispatcher.respond(DesktopFrontendMessage::PersistenceWriteDocument {
id: document_id,
document: Document {
content: document,
name: details.name,
path: details.path,
is_saved: details.is_saved,
},
});
FrontendMessage::TriggerPersistenceReadState => {
dispatcher.respond(DesktopFrontendMessage::PersistenceReadState);
}
FrontendMessage::TriggerPersistenceRemoveDocument { document_id } => {
FrontendMessage::TriggerPersistenceWriteState { state } => {
dispatcher.respond(DesktopFrontendMessage::PersistenceWriteState { state });
}
FrontendMessage::TriggerPersistenceReadDocument { document_id } => {
dispatcher.respond(DesktopFrontendMessage::PersistenceReadDocument { id: document_id });
}
FrontendMessage::TriggerPersistenceDeleteDocument { document_id } => {
dispatcher.respond(DesktopFrontendMessage::PersistenceDeleteDocument { id: document_id });
}
FrontendMessage::UpdateActiveDocument { document_id } => {
dispatcher.respond(DesktopFrontendMessage::PersistenceUpdateCurrentDocument { id: document_id });
// Forward this to update the UI
return Some(FrontendMessage::UpdateActiveDocument { document_id });
}
FrontendMessage::UpdateOpenDocumentsList { open_documents } => {
dispatcher.respond(DesktopFrontendMessage::PersistenceUpdateDocumentsList {
ids: open_documents.iter().map(|document| document.id).collect(),
FrontendMessage::TriggerPersistenceWriteDocument { document_id, document } => {
dispatcher.respond(DesktopFrontendMessage::PersistenceWriteDocument {
id: document_id,
document_serialized_content: document,
});
// Forward this to update the UI
return Some(FrontendMessage::UpdateOpenDocumentsList { open_documents });
}
FrontendMessage::TriggerLoadAutoSaveDocuments => {
dispatcher.respond(DesktopFrontendMessage::PersistenceLoadDocuments);
}
FrontendMessage::TriggerOpenLaunchDocuments => {
dispatcher.respond(DesktopFrontendMessage::OpenLaunchDocuments);
@@ -107,16 +94,6 @@ pub(super) fn intercept_frontend_message(dispatcher: &mut DesktopWrapperMessageD
FrontendMessage::TriggerLoadPreferences => {
dispatcher.respond(DesktopFrontendMessage::PersistenceLoadPreferences);
}
FrontendMessage::TriggerSaveWorkspaceLayout { workspace_layout } => {
let Ok(workspace_layout) = ron::ser::to_string_pretty(&workspace_layout, ron::ser::PrettyConfig::default()) else {
tracing::error!("Failed to serialize workspace layout");
return None;
};
dispatcher.respond(DesktopFrontendMessage::PersistenceWriteWorkspaceLayout { workspace_layout });
}
FrontendMessage::TriggerLoadWorkspaceLayout => {
dispatcher.respond(DesktopFrontendMessage::PersistenceLoadWorkspaceLayout);
}
#[cfg(target_os = "macos")]
FrontendMessage::UpdateLayout {
layout_target: LayoutTarget::MenuBar,

View File

@@ -3,7 +3,7 @@ use std::path::PathBuf;
pub(crate) use graphite_editor::messages::prelude::Message as EditorMessage;
pub use graphite_editor::messages::frontend::utility_types::{PersistedDocumentInfo, PersistedState};
pub use graphite_editor::messages::frontend::utility_types::{DocumentInfo, PersistedState};
pub use graphite_editor::messages::input_mapper::utility_types::input_keyboard::{Key, ModifierKeys};
pub use graphite_editor::messages::input_mapper::utility_types::input_mouse::{EditorMouseState as MouseState, EditorPosition as Position, MouseKeys};
pub use graphite_editor::messages::prelude::DocumentId;
@@ -42,26 +42,22 @@ pub enum DesktopFrontendMessage {
UpdateOverlays(vello::Scene),
PersistenceWriteDocument {
id: DocumentId,
document: Document,
document_serialized_content: String,
},
PersistenceDeleteDocument {
id: DocumentId,
},
PersistenceUpdateCurrentDocument {
id: DocumentId,
},
PersistenceLoadDocuments,
PersistenceUpdateDocumentsList {
ids: Vec<DocumentId>,
},
PersistenceWritePreferences {
preferences: Preferences,
},
PersistenceLoadPreferences,
PersistenceWriteWorkspaceLayout {
workspace_layout: String,
PersistenceWriteState {
state: PersistedState,
},
PersistenceReadState,
PersistenceReadDocument {
id: DocumentId,
},
PersistenceLoadWorkspaceLayout,
UpdateMenu {
entries: Vec<MenuItem>,
},
@@ -85,66 +81,20 @@ pub enum DesktopFrontendMessage {
pub enum DesktopWrapperMessage {
FromWeb(Box<EditorMessage>),
Input(InputMessage),
FileDialogResult {
path: PathBuf,
content: Vec<u8>,
context: OpenFileDialogContext,
},
SaveFileDialogResult {
path: PathBuf,
context: SaveFileDialogContext,
},
OpenFile {
path: PathBuf,
content: Vec<u8>,
},
ImportFile {
path: PathBuf,
content: Vec<u8>,
},
FileDialogResult { path: PathBuf, content: Vec<u8>, context: OpenFileDialogContext },
SaveFileDialogResult { path: PathBuf, context: SaveFileDialogContext },
OpenFile { path: PathBuf, content: Vec<u8> },
ImportFile { path: PathBuf, content: Vec<u8> },
PollNodeGraphEvaluation,
UpdateMaximized {
maximized: bool,
},
UpdateFullscreen {
fullscreen: bool,
},
LoadDocument {
id: DocumentId,
document: Document,
to_front: bool,
select_after_open: bool,
},
SelectDocument {
id: DocumentId,
},
LoadPreferences {
preferences: Preferences,
},
LoadWorkspaceLayout {
workspace_layout: String,
},
MenuEvent {
id: String,
},
ClipboardReadResult {
content: Option<String>,
},
PointerLockMove {
x: f64,
y: f64,
},
LoadThirdPartyLicenses {
text: String,
},
}
#[derive(Clone, serde::Serialize, serde::Deserialize, Debug)]
pub struct Document {
pub content: String,
pub name: String,
pub path: Option<PathBuf>,
pub is_saved: bool,
UpdateMaximized { maximized: bool },
UpdateFullscreen { fullscreen: bool },
LoadDocumentContent { id: DocumentId, document: String },
LoadPersistedState { state: PersistedState },
LoadPreferences { preferences: Preferences },
MenuEvent { id: String },
ClipboardReadResult { content: Option<String> },
PointerLockMove { x: f64, y: f64 },
LoadThirdPartyLicenses { text: String },
}
pub struct FileFilter {