Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e1aaee1
removed all use of document indicies
mfish33 Dec 18, 2021
d3e3ab6
-add u64 support for wasm bridge
mfish33 Dec 19, 2021
51c1056
fixed rust formating
mfish33 Dec 19, 2021
f73a631
Merge branch 'master' into only-document-ids
mfish33 Dec 20, 2021
b720ef9
Merge branch 'master' into only-document-ids
Keavon Dec 20, 2021
9483fae
Cleaned up FrontendDocumentState in js-messages
mfish33 Dec 20, 2021
833f1f9
Merge branch 'only-document-ids' of https://github.com/GraphiteEditor…
mfish33 Dec 20, 2021
f9e2cbb
Merge branch 'master' into only-document-ids
Keavon Dec 20, 2021
8574683
Tiny tweaks from code review
Keavon Dec 21, 2021
e1a0308
- moved more of closeDocumentWithConfirmation to rust
mfish33 Dec 22, 2021
fb4edec
Merge branch 'only-document-ids' of https://github.com/GraphiteEditor…
mfish33 Dec 22, 2021
fe55503
Merge branch 'master' into only-document-ids
mfish33 Dec 22, 2021
161c2bf
Merge branch 'master' into only-document-ids
mfish33 Dec 23, 2021
0599861
working initial auto save impl
mfish33 Dec 24, 2021
65afd61
auto save is a lifetime file
mfish33 Dec 26, 2021
6feaf74
Merge branch 'master' into indexed-db-auto-save
mfish33 Dec 26, 2021
82e146f
- cargo fmt
mfish33 Dec 26, 2021
9a9ac45
Merge branch 'master' into indexed-db-auto-save
Keavon Dec 26, 2021
3400200
code review round 1
mfish33 Dec 27, 2021
b9a6100
Merge branch 'indexed-db-auto-save' of https://github.com/GraphiteEdi…
mfish33 Dec 27, 2021
d81acdd
generate seed for uuid in js when wasm is initialized
mfish33 Dec 27, 2021
45b0355
Resolve PR feedback
otdavies Dec 27, 2021
b70bea8
Further address PR feedback
otdavies Dec 27, 2021
e135a74
Fix failing test
Keavon Dec 27, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions editor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ thiserror = "1.0.24"
serde = { version = "1.0", features = ["derive"] }
graphite-proc-macros = { path = "../proc-macros" }
glam = { version="0.17", features = ["serde"] }
rand = "0.8.4"
rand_chacha = "0.3.1"
getrandom = "0.2.3"
spin = "0.9.2"
kurbo = { git = "https://github.com/GraphiteEditor/kurbo.git", features = [
"serde",
Expand All @@ -29,3 +31,6 @@ package = "graphite-graphene"

[dev-dependencies]
env_logger = "0.8.4"

[features]
js = ["getrandom/js"]
Comment thread
otdavies marked this conversation as resolved.
Outdated
2 changes: 1 addition & 1 deletion editor/src/communication/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ where
pub fn generate_uuid() -> u64 {
let mut lock = RNG.lock();
if lock.is_none() {
*lock = Some(ChaCha20Rng::seed_from_u64(0));
*lock = Some(ChaCha20Rng::from_entropy());
}
lock.as_mut().map(ChaCha20Rng::next_u64).unwrap()
}
11 changes: 10 additions & 1 deletion editor/src/document/document_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,14 @@ impl DocumentMessageHandler {
self.current_identifier() == self.saved_document_identifier
}

pub fn saved(&mut self, state: bool) {
if state {
Comment thread
otdavies marked this conversation as resolved.
Outdated
self.saved_document_identifier = self.current_identifier();
} else {
self.saved_document_identifier = generate_uuid();
}
}

pub fn layer_panel_entry(&mut self, path: Vec<LayerId>) -> Result<LayerPanelEntry, EditorError> {
let data: LayerData = *layer_data(&mut self.layer_data, &path);
let layer = self.graphene_document.layer(&path)?;
Expand Down Expand Up @@ -493,7 +501,8 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
)
}
SaveDocument => {
self.saved_document_identifier = self.current_identifier();
self.saved(true);
Comment thread
Keavon marked this conversation as resolved.
Outdated
responses.push_back(DocumentsMessage::AutoSaveActiveDocument.into());
// Update the save status of the just saved document
responses.push_back(DocumentsMessage::UpdateOpenDocumentsList.into());

Expand Down
83 changes: 65 additions & 18 deletions editor/src/document/document_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,16 @@ pub enum DocumentsMessage {
RequestAboutGraphiteDialog,
NewDocument,
OpenDocument,
OpenDocumentFileWithId {
document: String,
document_name: String,
document_id: u64,
document_is_saved: bool,
},
OpenDocumentFile(String, String),
UpdateOpenDocumentsList,
AutoSaveDocument(u64),
AutoSaveActiveDocument,
NextDocument,
PrevDocument,
}
Expand Down Expand Up @@ -76,11 +84,19 @@ impl DocumentsMessageHandler {
name
}

fn load_document(&mut self, new_document: DocumentMessageHandler, responses: &mut VecDeque<Message>) {
let new_id = generate_uuid();
self.active_document_id = new_id;
self.document_ids.push(new_id);
self.documents.insert(new_id, new_document);
fn load_document(&mut self, new_document: DocumentMessageHandler, document_id: u64, replace_first_empty: bool, responses: &mut VecDeque<Message>) {
// Special case when loading a document on an empty page
if replace_first_empty && self.document_ids.len() == 1 {
let first_id = self.document_ids[0];
let first_document = self.documents.get(&first_id).unwrap();
if first_document.serialize_root().len() == 2 {
Comment thread
otdavies marked this conversation as resolved.
Outdated
// The first document must not have been touched
responses.push_back(DocumentsMessage::CloseDocument(first_id).into());
}
}

self.document_ids.push(document_id);
self.documents.insert(document_id, new_document);

// Send the new list of document tab names
let open_documents = self
Expand All @@ -97,12 +113,7 @@ impl DocumentsMessageHandler {

responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into());

responses.push_back(DocumentsMessage::SelectDocument(self.active_document_id).into());
responses.push_back(DocumentMessage::RenderDocument.into());
responses.push_back(DocumentMessage::DocumentStructureChanged.into());
for layer in self.active_document().layer_data.keys() {
responses.push_back(DocumentMessage::LayerChanged(layer.clone()).into());
}
responses.push_back(DocumentsMessage::SelectDocument(document_id).into());
}

// Returns an iterator over the open documents in order
Expand Down Expand Up @@ -140,6 +151,10 @@ impl MessageHandler<DocumentsMessage, &InputPreprocessor> for DocumentsMessageHa
}
Document(message) => self.active_document_mut().process_action(message, ipp, responses),
SelectDocument(id) => {
let active_document = self.active_document();
if !active_document.is_saved() {
responses.push_back(DocumentsMessage::AutoSaveDocument(self.active_document_id).into());
}
self.active_document_id = id;
responses.push_back(FrontendMessage::SetActiveDocument { document_id: id }.into());
responses.push_back(RenderDocument.into());
Expand Down Expand Up @@ -210,6 +225,7 @@ impl MessageHandler<DocumentsMessage, &InputPreprocessor> for DocumentsMessageHa
// Update the list of new documents on the front end, active tab, and ensure that document renders
responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into());
responses.push_back(FrontendMessage::SetActiveDocument { document_id: self.active_document_id }.into());
responses.push_back(FrontendMessage::RemoveAutoSaveDocument { document_id: id }.into());
responses.push_back(RenderDocument.into());
responses.push_back(DocumentMessage::DocumentStructureChanged.into());
for layer in self.active_document().layer_data.keys() {
Expand All @@ -219,16 +235,32 @@ impl MessageHandler<DocumentsMessage, &InputPreprocessor> for DocumentsMessageHa
NewDocument => {
let name = self.generate_new_document_name();
let new_document = DocumentMessageHandler::with_name(name, ipp);
self.load_document(new_document, responses);
self.load_document(new_document, generate_uuid(), false, responses);
}
OpenDocument => {
responses.push_back(FrontendMessage::OpenDocumentBrowse.into());
}
OpenDocumentFile(name, serialized_contents) => {
let document = DocumentMessageHandler::with_name_and_content(name, serialized_contents, ipp);
OpenDocumentFile(document_name, document) => responses.push_back(
Comment thread
otdavies marked this conversation as resolved.
Outdated
DocumentsMessage::OpenDocumentFileWithId {
document,
document_name,
document_id: generate_uuid(),
document_is_saved: true,
}
.into(),
),
OpenDocumentFileWithId {
document_name,
document_id,
document,
document_is_saved,
} => {
let document = DocumentMessageHandler::with_name_and_content(document_name, document, ipp);
match document {
Ok(document) => {
self.load_document(document, responses);
Ok(mut document) => {
log::debug!("Setting Saved: {}", document_is_saved);
Comment thread
otdavies marked this conversation as resolved.
Outdated
document.saved(document_is_saved);
self.load_document(document, document_id, true, responses);
}
Err(e) => responses.push_back(
FrontendMessage::DisplayError {
Expand All @@ -254,18 +286,33 @@ impl MessageHandler<DocumentsMessage, &InputPreprocessor> for DocumentsMessageHa
.collect::<Vec<_>>();
responses.push_back(FrontendMessage::UpdateOpenDocumentsList { open_documents }.into());
}
AutoSaveDocument(id) => {
let document = self.documents.get(&id).unwrap();
responses.push_back(
FrontendMessage::AutoSaveDocument {
document: document.graphene_document.serialize_document(),
details: FrontendDocumentDetails {
is_saved: document.is_saved(),
id,
name: document.name.clone(),
},
}
.into(),
)
}
AutoSaveActiveDocument => responses.push_back(DocumentsMessage::AutoSaveDocument(self.active_document_id).into()),
NextDocument => {
let current_index = self.document_index(self.active_document_id);
let next_index = (current_index + 1) % self.document_ids.len();
let next_id = self.document_ids[next_index];
responses.push_back(SelectDocument(next_id).into());
responses.push_back(DocumentsMessage::SelectDocument(next_id).into());
}
PrevDocument => {
let len = self.document_ids.len();
let current_index = self.document_index(self.active_document_id);
let prev_index = (current_index + len - 1) % len;
let prev_id = self.document_ids[prev_index];
responses.push_back(SelectDocument(prev_id).into());
responses.push_back(DocumentsMessage::SelectDocument(prev_id).into());
}
Copy => {
let paths = self.active_document().selected_layers_sorted();
Expand Down
1 change: 0 additions & 1 deletion editor/src/document/movement_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::{
input::{mouse::ViewportBounds, mouse::ViewportPosition, InputPreprocessor},
};
use graphene::document::Document;
use graphene::layers::style::ViewMode;
use graphene::Operation as DocumentOperation;

use glam::DVec2;
Expand Down
2 changes: 2 additions & 0 deletions editor/src/frontend/frontend_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ pub enum FrontendMessage {
UpdateRulers { origin: (f64, f64), spacing: f64, interval: f64 },
ExportDocument { document: String, name: String },
SaveDocument { document: String, name: String },
AutoSaveDocument { document: String, details: FrontendDocumentDetails },
RemoveAutoSaveDocument { document_id: u64 },
OpenDocumentBrowse,
UpdateWorkingColors { primary: Color, secondary: Color },
SetCanvasZoom { new_zoom: f64 },
Expand Down
4 changes: 2 additions & 2 deletions editor/src/tool/tools/eyedropper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ impl Fsm for EyedropperToolFsmState {
self,
event: ToolMessage,
document: &DocumentMessageHandler,
tool_data: &DocumentToolData,
data: &mut Self::ToolData,
_tool_data: &DocumentToolData,
_data: &mut Self::ToolData,
input: &InputPreprocessor,
responses: &mut VecDeque<Message>,
) -> Self {
Expand Down
2 changes: 1 addition & 1 deletion editor/src/tool/tools/fill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ impl Fsm for FillToolFsmState {
event: ToolMessage,
document: &DocumentMessageHandler,
tool_data: &DocumentToolData,
data: &mut Self::ToolData,
_data: &mut Self::ToolData,
input: &InputPreprocessor,
responses: &mut VecDeque<Message>,
) -> Self {
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ import LayoutRow from "@/components/layout/LayoutRow.vue";
import { createEditorState, EditorState } from "@/state/wasm-loader";
import { createInputManager, InputManager } from "@/lifetime/input";
import { initErrorHandling } from "@/lifetime/errors";
import { createAutoSave } from "@/lifetime/auto-save";

// Vue injects don't play well with TypeScript, and all injects will show up as `any`. As a workaround, we can define these types.
declare module "@vue/runtime-core" {
Expand Down Expand Up @@ -259,6 +260,7 @@ export default defineComponent({
const documents = createDocumentsState(editor, dialog);
const fullscreen = createFullscreenState();
initErrorHandling(editor, dialog);
createAutoSave(editor, documents);

return {
editor,
Expand Down
21 changes: 21 additions & 0 deletions frontend/src/dispatcher/js-messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,25 @@ export const LayerTypeOptions = {

export type LayerType = typeof LayerTypeOptions[keyof typeof LayerTypeOptions];

export class FrontendDocumentDetailsIndexedDb extends FrontendDocumentDetails {
@Transform(({ value }: { value: BigInt }) => value.toString())
// @ts-expect-error Use a string since IndexedDB can not use BigInts for keys
id!: string;
}

export class AutoSaveDocument extends JsMessage {
document!: string;

@Type(() => FrontendDocumentDetailsIndexedDb)
details!: FrontendDocumentDetailsIndexedDb;
}

export class RemoveAutoSaveDocument extends JsMessage {
// Use a string since IndexedDB can not use BigInts for keys
@Transform(({ value }: { value: BigInt }) => value.toString())
document_id!: string;
}

// Any is used since the type of the object should be known from the rust side
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type JSMessageFactory = (data: any, wasm: WasmInstance, instance: RustEditorInstance) => JsMessage;
Expand All @@ -322,5 +341,7 @@ export const messageConstructors: Record<string, MessageMaker> = {
DisplayConfirmationToCloseDocument,
DisplayConfirmationToCloseAllDocuments,
DisplayAboutGraphiteDialog,
AutoSaveDocument,
RemoveAutoSaveDocument,
} as const;
export type JsMessageType = keyof typeof messageConstructors;
Loading