mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-27 15:38:11 +08:00
Desktop: Move preferences persistence to native (#3138)
* Move preference persistence to native * Pass preferences as struct instead of serialized to string
This commit is contained in:
Generated
+1
@@ -2365,6 +2365,7 @@ dependencies = [
|
|||||||
"ron",
|
"ron",
|
||||||
"serde",
|
"serde",
|
||||||
"serde-wasm-bindgen",
|
"serde-wasm-bindgen",
|
||||||
|
"serde_json",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
|
|||||||
@@ -214,6 +214,15 @@ impl WinitApp {
|
|||||||
self.dispatch_desktop_wrapper_message(message);
|
self.dispatch_desktop_wrapper_message(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DesktopFrontendMessage::PersistenceWritePreferences { preferences } => {
|
||||||
|
self.persistent_data.write_preferences(preferences);
|
||||||
|
}
|
||||||
|
DesktopFrontendMessage::PersistenceLoadPreferences => {
|
||||||
|
if let Some(preferences) = self.persistent_data.load_preferences() {
|
||||||
|
let message = DesktopWrapperMessage::LoadPreferences { preferences };
|
||||||
|
self.dispatch_desktop_wrapper_message(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
pub(crate) static APP_NAME: &str = "Graphite";
|
pub(crate) static APP_NAME: &str = "Graphite";
|
||||||
pub(crate) static APP_ID: &str = "rs.graphite.GraphiteEditor";
|
pub(crate) static APP_ID: &str = "rs.graphite.GraphiteEditor";
|
||||||
|
|
||||||
pub(crate) static APP_DIRECTORY_NAME: &str = "graphite-editor";
|
pub(crate) static APP_DIRECTORY_NAME: &str = "graphite-editor";
|
||||||
pub(crate) static APP_AUTOSAVE_DIRECTORY_NAME: &str = "documents";
|
pub(crate) static APP_STATE_FILE_NAME: &str = "state.ron";
|
||||||
|
pub(crate) static APP_PREFERENCES_FILE_NAME: &str = "preferences.ron";
|
||||||
|
pub(crate) static APP_DOCUMENTS_DIRECTORY_NAME: &str = "documents";
|
||||||
|
|
||||||
// CEF configuration constants
|
// CEF configuration constants
|
||||||
pub(crate) const CEF_WINDOWLESS_FRAME_RATE: i32 = 60;
|
pub(crate) const CEF_WINDOWLESS_FRAME_RATE: i32 = 60;
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
use std::fs::create_dir_all;
|
use std::fs::create_dir_all;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::consts::{APP_AUTOSAVE_DIRECTORY_NAME, APP_DIRECTORY_NAME};
|
use crate::consts::{APP_DIRECTORY_NAME, APP_DOCUMENTS_DIRECTORY_NAME};
|
||||||
|
|
||||||
pub(crate) fn ensure_dir_exists(path: &PathBuf) {
|
pub(crate) fn ensure_dir_exists(path: &PathBuf) {
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
@@ -16,7 +16,7 @@ pub(crate) fn graphite_data_dir() -> PathBuf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn graphite_autosave_documents_dir() -> PathBuf {
|
pub(crate) fn graphite_autosave_documents_dir() -> PathBuf {
|
||||||
let path = graphite_data_dir().join(APP_AUTOSAVE_DIRECTORY_NAME);
|
let path = graphite_data_dir().join(APP_DOCUMENTS_DIRECTORY_NAME);
|
||||||
ensure_dir_exists(&path);
|
ensure_dir_exists(&path);
|
||||||
path
|
path
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-6
@@ -1,4 +1,4 @@
|
|||||||
use graphite_desktop_wrapper::messages::{Document, DocumentId};
|
use graphite_desktop_wrapper::messages::{Document, DocumentId, Preferences};
|
||||||
|
|
||||||
#[derive(Default, serde::Serialize, serde::Deserialize)]
|
#[derive(Default, serde::Serialize, serde::Deserialize)]
|
||||||
pub(crate) struct PersistentData {
|
pub(crate) struct PersistentData {
|
||||||
@@ -6,6 +6,7 @@ pub(crate) struct PersistentData {
|
|||||||
current_document: Option<DocumentId>,
|
current_document: Option<DocumentId>,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
document_order: Option<Vec<DocumentId>>,
|
document_order: Option<Vec<DocumentId>>,
|
||||||
|
preferences: Option<Preferences>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PersistentData {
|
impl PersistentData {
|
||||||
@@ -72,21 +73,37 @@ impl PersistentData {
|
|||||||
self.flush();
|
self.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn write_preferences(&mut self, preferences: Preferences) {
|
||||||
|
let Ok(preferences) = ron::ser::to_string_pretty(&preferences, Default::default()) else {
|
||||||
|
tracing::error!("Failed to serialize preferences");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
std::fs::write(Self::preferences_file_path(), &preferences).unwrap_or_else(|e| {
|
||||||
|
tracing::error!("Failed to write preferences to disk: {e}");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn load_preferences(&self) -> Option<Preferences> {
|
||||||
|
let data = std::fs::read_to_string(Self::preferences_file_path()).ok()?;
|
||||||
|
let preferences = ron::from_str(&data).ok()?;
|
||||||
|
Some(preferences)
|
||||||
|
}
|
||||||
|
|
||||||
fn flush(&self) {
|
fn flush(&self) {
|
||||||
let data = match ron::to_string(self) {
|
let data = match ron::ser::to_string_pretty(self, Default::default()) {
|
||||||
Ok(d) => d,
|
Ok(d) => d,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::error!("Failed to serialize persistent data: {e}");
|
tracing::error!("Failed to serialize persistent data: {e}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Err(e) = std::fs::write(Self::persistence_file_path(), data) {
|
if let Err(e) = std::fs::write(Self::state_file_path(), data) {
|
||||||
tracing::error!("Failed to write persistent data to disk: {e}");
|
tracing::error!("Failed to write persistent data to disk: {e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn load_from_disk(&mut self) {
|
pub(crate) fn load_from_disk(&mut self) {
|
||||||
let path = Self::persistence_file_path();
|
let path = Self::state_file_path();
|
||||||
let data = match std::fs::read_to_string(&path) {
|
let data = match std::fs::read_to_string(&path) {
|
||||||
Ok(d) => d,
|
Ok(d) => d,
|
||||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
|
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
|
||||||
@@ -108,9 +125,15 @@ impl PersistentData {
|
|||||||
*self = loaded;
|
*self = loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn persistence_file_path() -> std::path::PathBuf {
|
fn state_file_path() -> std::path::PathBuf {
|
||||||
let mut path = crate::dirs::graphite_data_dir();
|
let mut path = crate::dirs::graphite_data_dir();
|
||||||
path.push(format!("{}.ron", crate::consts::APP_AUTOSAVE_DIRECTORY_NAME));
|
path.push(crate::consts::APP_STATE_FILE_NAME);
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preferences_file_path() -> std::path::PathBuf {
|
||||||
|
let mut path = crate::dirs::graphite_data_dir();
|
||||||
|
path.push(crate::consts::APP_PREFERENCES_FILE_NAME);
|
||||||
path
|
path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use graphene_std::Color;
|
use graphene_std::Color;
|
||||||
use graphene_std::raster::Image;
|
use graphene_std::raster::Image;
|
||||||
use graphite_editor::messages::app_window::app_window_message_handler::AppWindowPlatform;
|
use graphite_editor::messages::app_window::app_window_message_handler::AppWindowPlatform;
|
||||||
use graphite_editor::messages::prelude::{AppWindowMessage, DocumentMessage, PortfolioMessage};
|
use graphite_editor::messages::prelude::{AppWindowMessage, DocumentMessage, PortfolioMessage, PreferencesMessage};
|
||||||
|
|
||||||
use crate::messages::Platform;
|
use crate::messages::Platform;
|
||||||
|
|
||||||
@@ -140,5 +140,9 @@ pub(super) fn handle_desktop_wrapper_message(dispatcher: &mut DesktopWrapperMess
|
|||||||
let message = PortfolioMessage::SelectDocument { document_id: id };
|
let message = PortfolioMessage::SelectDocument { document_id: id };
|
||||||
dispatcher.queue_editor_message(message.into());
|
dispatcher.queue_editor_message(message.into());
|
||||||
}
|
}
|
||||||
|
DesktopWrapperMessage::LoadPreferences { preferences } => {
|
||||||
|
let message = PreferencesMessage::Load { preferences };
|
||||||
|
dispatcher.queue_editor_message(message.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,6 +107,12 @@ pub(super) fn intercept_frontend_message(dispatcher: &mut DesktopWrapperMessageD
|
|||||||
FrontendMessage::TriggerLoadRestAutoSaveDocuments => {
|
FrontendMessage::TriggerLoadRestAutoSaveDocuments => {
|
||||||
dispatcher.respond(DesktopFrontendMessage::PersistenceLoadRemainingDocuments);
|
dispatcher.respond(DesktopFrontendMessage::PersistenceLoadRemainingDocuments);
|
||||||
}
|
}
|
||||||
|
FrontendMessage::TriggerSavePreferences { preferences } => {
|
||||||
|
dispatcher.respond(DesktopFrontendMessage::PersistenceWritePreferences { preferences });
|
||||||
|
}
|
||||||
|
FrontendMessage::TriggerLoadPreferences => {
|
||||||
|
dispatcher.respond(DesktopFrontendMessage::PersistenceLoadPreferences);
|
||||||
|
}
|
||||||
m => return Some(m),
|
m => return Some(m),
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
pub use graphite_editor::messages::prelude::DocumentId;
|
pub use graphite_editor::messages::prelude::DocumentId;
|
||||||
use graphite_editor::messages::prelude::FrontendMessage;
|
use graphite_editor::messages::prelude::FrontendMessage;
|
||||||
pub(crate) use graphite_editor::messages::prelude::Message as EditorMessage;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
pub(crate) use graphite_editor::messages::prelude::Message as EditorMessage;
|
||||||
|
|
||||||
|
pub use graphite_editor::messages::prelude::PreferencesMessageHandler as Preferences;
|
||||||
|
|
||||||
pub enum DesktopFrontendMessage {
|
pub enum DesktopFrontendMessage {
|
||||||
ToWeb(Vec<FrontendMessage>),
|
ToWeb(Vec<FrontendMessage>),
|
||||||
OpenFileDialog {
|
OpenFileDialog {
|
||||||
@@ -48,6 +51,10 @@ pub enum DesktopFrontendMessage {
|
|||||||
PersistenceUpdateDocumentsList {
|
PersistenceUpdateDocumentsList {
|
||||||
ids: Vec<DocumentId>,
|
ids: Vec<DocumentId>,
|
||||||
},
|
},
|
||||||
|
PersistenceWritePreferences {
|
||||||
|
preferences: Preferences,
|
||||||
|
},
|
||||||
|
PersistenceLoadPreferences,
|
||||||
CloseWindow,
|
CloseWindow,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +100,9 @@ pub enum DesktopWrapperMessage {
|
|||||||
SelectDocument {
|
SelectDocument {
|
||||||
id: DocumentId,
|
id: DocumentId,
|
||||||
},
|
},
|
||||||
|
LoadPreferences {
|
||||||
|
preferences: Preferences,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, serde::Serialize, serde::Deserialize, Debug)]
|
#[derive(Clone, serde::Serialize, serde::Deserialize, Debug)]
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use crate::messages::prelude::*;
|
|||||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum PreferencesMessage {
|
pub enum PreferencesMessage {
|
||||||
// Management messages
|
// Management messages
|
||||||
Load { preferences: String },
|
Load { preferences: PreferencesMessageHandler },
|
||||||
ResetToDefaults,
|
ResetToDefaults,
|
||||||
|
|
||||||
// Per-preference messages
|
// Per-preference messages
|
||||||
|
|||||||
@@ -50,15 +50,13 @@ impl MessageHandler<PreferencesMessage, ()> for PreferencesMessageHandler {
|
|||||||
match message {
|
match message {
|
||||||
// Management messages
|
// Management messages
|
||||||
PreferencesMessage::Load { preferences } => {
|
PreferencesMessage::Load { preferences } => {
|
||||||
if let Ok(deserialized_preferences) = serde_json::from_str::<PreferencesMessageHandler>(&preferences) {
|
*self = preferences;
|
||||||
*self = deserialized_preferences;
|
|
||||||
|
|
||||||
responses.add(PortfolioMessage::EditorPreferences);
|
responses.add(PortfolioMessage::EditorPreferences);
|
||||||
responses.add(PortfolioMessage::UpdateVelloPreference);
|
responses.add(PortfolioMessage::UpdateVelloPreference);
|
||||||
responses.add(PreferencesMessage::ModifyLayout {
|
responses.add(PreferencesMessage::ModifyLayout {
|
||||||
zoom_with_scroll: self.zoom_with_scroll,
|
zoom_with_scroll: self.zoom_with_scroll,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
PreferencesMessage::ResetToDefaults => {
|
PreferencesMessage::ResetToDefaults => {
|
||||||
refresh_dialog(responses);
|
refresh_dialog(responses);
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ math-parser = { workspace = true }
|
|||||||
wgpu = { workspace = true }
|
wgpu = { workspace = true }
|
||||||
web-sys = { workspace = true }
|
web-sys = { workspace = true }
|
||||||
ron = { workspace = true }
|
ron = { workspace = true }
|
||||||
|
serde_json = { workspace = true }
|
||||||
|
|
||||||
[package.metadata.wasm-pack.profile.dev]
|
[package.metadata.wasm-pack.profile.dev]
|
||||||
wasm-opt = false
|
wasm-opt = false
|
||||||
|
|||||||
@@ -415,6 +415,11 @@ impl EditorHandle {
|
|||||||
|
|
||||||
#[wasm_bindgen(js_name = loadPreferences)]
|
#[wasm_bindgen(js_name = loadPreferences)]
|
||||||
pub fn load_preferences(&self, preferences: String) {
|
pub fn load_preferences(&self, preferences: String) {
|
||||||
|
let Ok(preferences) = serde_json::from_str(&preferences) else {
|
||||||
|
log::error!("Failed to deserialize preferences");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let message = PreferencesMessage::Load { preferences };
|
let message = PreferencesMessage::Load { preferences };
|
||||||
|
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
|
|||||||
Reference in New Issue
Block a user