mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Refactor persistent data storage code and add button to wipe data on crash (#827)
* Organize persistence.ts * Switch to simpler promise handling * Switch document list storage from localStorage to IndexedDB * Track document auto-save status to avoid re-auto-saving unnecessarily * Add button to clear storage on crash * Bump document version and test file * Switch to IDB-Keyval instead of raw IDB transactions
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -74,7 +74,7 @@ pub const DEFAULT_FONT_FAMILY: &str = "Merriweather";
|
||||
pub const DEFAULT_FONT_STYLE: &str = "Normal (400)";
|
||||
|
||||
// Document
|
||||
pub const GRAPHITE_DOCUMENT_VERSION: &str = "0.0.14"; // Remember to save a simple document and replace the test file `graphite-test-document.graphite`
|
||||
pub const GRAPHITE_DOCUMENT_VERSION: &str = "0.0.15"; // Remember to save a simple document and replace the test file `graphite-test-document.graphite`
|
||||
pub const DEFAULT_DOCUMENT_NAME: &str = "Untitled Document";
|
||||
pub const FILE_SAVE_SUFFIX: &str = ".graphite";
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct FrontendDocumentDetails {
|
||||
#[serde(rename = "isAutoSaved")]
|
||||
pub is_auto_saved: bool,
|
||||
#[serde(rename = "isSaved")]
|
||||
pub is_saved: bool,
|
||||
pub name: String,
|
||||
|
||||
@@ -37,6 +37,7 @@ use serde::{Deserialize, Serialize};
|
||||
pub struct DocumentMessageHandler {
|
||||
pub graphene_document: GrapheneDocument,
|
||||
pub saved_document_identifier: u64,
|
||||
pub auto_saved_document_identifier: u64,
|
||||
pub name: String,
|
||||
pub version: String,
|
||||
|
||||
@@ -68,6 +69,7 @@ impl Default for DocumentMessageHandler {
|
||||
Self {
|
||||
graphene_document: GrapheneDocument::default(),
|
||||
saved_document_identifier: 0,
|
||||
auto_saved_document_identifier: 0,
|
||||
name: String::from("Untitled Document"),
|
||||
version: GRAPHITE_DOCUMENT_VERSION.to_string(),
|
||||
|
||||
@@ -1354,10 +1356,22 @@ impl DocumentMessageHandler {
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
pub fn is_auto_saved(&self) -> bool {
|
||||
self.current_identifier() == self.auto_saved_document_identifier
|
||||
}
|
||||
|
||||
pub fn is_saved(&self) -> bool {
|
||||
self.current_identifier() == self.saved_document_identifier
|
||||
}
|
||||
|
||||
pub fn set_auto_save_state(&mut self, is_saved: bool) {
|
||||
if is_saved {
|
||||
self.auto_saved_document_identifier = self.current_identifier();
|
||||
} else {
|
||||
self.auto_saved_document_identifier = generate_uuid();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_save_state(&mut self, is_saved: bool) {
|
||||
if is_saved {
|
||||
self.saved_document_identifier = self.current_identifier();
|
||||
|
||||
@@ -92,6 +92,7 @@ pub enum PortfolioMessage {
|
||||
OpenDocumentFileWithId {
|
||||
document_id: u64,
|
||||
document_name: String,
|
||||
document_is_auto_saved: bool,
|
||||
document_is_saved: bool,
|
||||
document_serialized_content: String,
|
||||
},
|
||||
|
||||
@@ -49,6 +49,9 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
||||
}
|
||||
PortfolioMessage::AutoSaveActiveDocument => {
|
||||
if let Some(document_id) = self.active_document_id {
|
||||
if let Some(document) = self.active_document_mut() {
|
||||
document.set_auto_save_state(true);
|
||||
}
|
||||
responses.push_back(PortfolioMessage::AutoSaveDocument { document_id }.into());
|
||||
}
|
||||
}
|
||||
@@ -58,6 +61,7 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
||||
FrontendMessage::TriggerIndexedDbWriteDocument {
|
||||
document: document.serialize_document(),
|
||||
details: FrontendDocumentDetails {
|
||||
is_auto_saved: document.is_auto_saved(),
|
||||
is_saved: document.is_saved(),
|
||||
id: document_id,
|
||||
name: document.name.clone(),
|
||||
@@ -93,24 +97,15 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
||||
|
||||
if self.document_ids.is_empty() {
|
||||
self.active_document_id = None;
|
||||
} else if Some(document_id) == self.active_document_id {
|
||||
if document_index == self.document_ids.len() {
|
||||
} else if self.active_document_id.is_some() {
|
||||
let document_id = if document_index == self.document_ids.len() {
|
||||
// If we closed the last document take the one previous (same as last)
|
||||
responses.push_back(
|
||||
PortfolioMessage::SelectDocument {
|
||||
document_id: *self.document_ids.last().unwrap(),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
*self.document_ids.last().unwrap()
|
||||
} else {
|
||||
// Move to the next tab
|
||||
responses.push_back(
|
||||
PortfolioMessage::SelectDocument {
|
||||
document_id: self.document_ids[document_index],
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
self.document_ids[document_index]
|
||||
};
|
||||
responses.push_back(PortfolioMessage::SelectDocument { document_id }.into());
|
||||
}
|
||||
|
||||
// Send the new list of document tab names
|
||||
@@ -282,6 +277,7 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
||||
PortfolioMessage::OpenDocumentFileWithId {
|
||||
document_id: generate_uuid(),
|
||||
document_name,
|
||||
document_is_auto_saved: false,
|
||||
document_is_saved: true,
|
||||
document_serialized_content,
|
||||
}
|
||||
@@ -291,12 +287,14 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
||||
PortfolioMessage::OpenDocumentFileWithId {
|
||||
document_id,
|
||||
document_name,
|
||||
document_is_auto_saved,
|
||||
document_is_saved,
|
||||
document_serialized_content,
|
||||
} => {
|
||||
let document = DocumentMessageHandler::with_name_and_content(document_name, document_serialized_content);
|
||||
match document {
|
||||
Ok(mut document) => {
|
||||
document.set_auto_save_state(document_is_auto_saved);
|
||||
document.set_save_state(document_is_saved);
|
||||
self.load_document(document, document_id, responses);
|
||||
}
|
||||
@@ -417,10 +415,10 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
||||
}
|
||||
PortfolioMessage::SelectDocument { document_id } => {
|
||||
if let Some(document) = self.active_document() {
|
||||
if !document.is_saved() {
|
||||
// Safe to unwrap since we know that there is an active document
|
||||
if !document.is_auto_saved() {
|
||||
responses.push_back(
|
||||
PortfolioMessage::AutoSaveDocument {
|
||||
// Safe to unwrap since we know that there is an active document
|
||||
document_id: self.active_document_id.unwrap(),
|
||||
}
|
||||
.into(),
|
||||
@@ -472,10 +470,11 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
||||
.document_ids
|
||||
.iter()
|
||||
.filter_map(|id| {
|
||||
self.documents.get(id).map(|doc| FrontendDocumentDetails {
|
||||
is_saved: doc.is_saved(),
|
||||
self.documents.get(id).map(|document| FrontendDocumentDetails {
|
||||
is_auto_saved: document.is_auto_saved(),
|
||||
is_saved: document.is_saved(),
|
||||
id: *id,
|
||||
name: doc.name.clone(),
|
||||
name: document.name.clone(),
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Reference in New Issue
Block a user