Skip to content

Commit 2be7790

Browse files
Improve UX of importing vs. opening files (#3661)
* wip * fix drag and drop * fix * fix tests * fix tests * fix warning * Partial code review * add dialog * fix web * fix web * push back release candidate expiry * Code review * Reduce code duplication for pasting files in frontend --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
1 parent 781fa7a commit 2be7790

23 files changed

Lines changed: 301 additions & 354 deletions

File tree

desktop/src/app.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ impl App {
180180
if let Some(path) = futures::executor::block_on(show_dialog)
181181
&& let Ok(content) = fs::read(&path)
182182
{
183-
let message = DesktopWrapperMessage::OpenFileDialogResult { path, content, context };
183+
let message = DesktopWrapperMessage::FileDialogResult { path, content, context };
184184
app_event_scheduler.schedule(AppEvent::DesktopWrapperMessage(message));
185185
}
186186
});
@@ -550,7 +550,7 @@ impl ApplicationHandler for App {
550550
for path in paths {
551551
match fs::read(&path) {
552552
Ok(content) => {
553-
let message = DesktopWrapperMessage::OpenFile { path, content };
553+
let message = DesktopWrapperMessage::ImportFile { path, content };
554554
self.app_event_scheduler.schedule(AppEvent::DesktopWrapperMessage(message));
555555
}
556556
Err(e) => {

desktop/src/persist.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ impl DocumentStore {
190190

191191
fn document_path(id: &DocumentId) -> std::path::PathBuf {
192192
let mut path = crate::dirs::app_autosave_documents_dir();
193-
path.push(format!("{:x}.graphite", id.0));
193+
path.push(format!("{:x}.{}", id.0, graphite_desktop_wrapper::FILE_EXTENSION));
194194
path
195195
}
196196
}

desktop/wrapper/src/handle_desktop_wrapper_message.rs

Lines changed: 5 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use graphene_std::Color;
2-
use graphene_std::raster::Image;
31
use graphite_editor::messages::clipboard::utility_types::ClipboardContentRaw;
42
use graphite_editor::messages::prelude::*;
53

@@ -14,9 +12,9 @@ pub(super) fn handle_desktop_wrapper_message(dispatcher: &mut DesktopWrapperMess
1412
DesktopWrapperMessage::Input(message) => {
1513
dispatcher.queue_editor_message(EditorMessage::InputPreprocessor(message));
1614
}
17-
DesktopWrapperMessage::OpenFileDialogResult { path, content, context } => match context {
18-
OpenFileDialogContext::Document => {
19-
dispatcher.queue_desktop_wrapper_message(DesktopWrapperMessage::OpenDocument { path, content });
15+
DesktopWrapperMessage::FileDialogResult { path, content, context } => match context {
16+
OpenFileDialogContext::Open => {
17+
dispatcher.queue_desktop_wrapper_message(DesktopWrapperMessage::OpenFile { path, content });
2018
}
2119
OpenFileDialogContext::Import => {
2220
dispatcher.queue_desktop_wrapper_message(DesktopWrapperMessage::ImportFile { path, content });
@@ -35,78 +33,11 @@ pub(super) fn handle_desktop_wrapper_message(dispatcher: &mut DesktopWrapperMess
3533
}
3634
},
3735
DesktopWrapperMessage::OpenFile { path, content } => {
38-
let extension = path.extension().and_then(|s| s.to_str()).unwrap_or_default().to_lowercase();
39-
match extension.as_str() {
40-
"graphite" => {
41-
dispatcher.queue_desktop_wrapper_message(DesktopWrapperMessage::OpenDocument { path, content });
42-
}
43-
_ => {
44-
dispatcher.queue_desktop_wrapper_message(DesktopWrapperMessage::ImportFile { path, content });
45-
}
46-
}
47-
}
48-
DesktopWrapperMessage::OpenDocument { path, content } => {
49-
let Ok(content) = String::from_utf8(content) else {
50-
tracing::warn!("Document file is invalid: {}", path.display());
51-
return;
52-
};
53-
54-
let message = PortfolioMessage::OpenDocumentFile {
55-
document_name: None,
56-
document_path: Some(path),
57-
document_serialized_content: content,
58-
};
36+
let message = PortfolioMessage::OpenFile { path, content };
5937
dispatcher.queue_editor_message(message);
6038
}
6139
DesktopWrapperMessage::ImportFile { path, content } => {
62-
let extension = path.extension().and_then(|s| s.to_str()).unwrap_or_default().to_lowercase();
63-
match extension.as_str() {
64-
"svg" => {
65-
dispatcher.queue_desktop_wrapper_message(DesktopWrapperMessage::ImportSvg { path, content });
66-
}
67-
_ => {
68-
dispatcher.queue_desktop_wrapper_message(DesktopWrapperMessage::ImportImage { path, content });
69-
}
70-
}
71-
}
72-
DesktopWrapperMessage::ImportSvg { path, content } => {
73-
let Ok(content) = String::from_utf8(content) else {
74-
tracing::warn!("Svg file is invalid: {}", path.display());
75-
return;
76-
};
77-
78-
let message = PortfolioMessage::PasteSvg {
79-
name: path.file_stem().map(|s| s.to_string_lossy().to_string()),
80-
svg: content,
81-
mouse: None,
82-
parent_and_insert_index: None,
83-
};
84-
dispatcher.queue_editor_message(message);
85-
}
86-
DesktopWrapperMessage::ImportImage { path, content } => {
87-
let name = path.file_stem().and_then(|s| s.to_str()).map(|s| s.to_string());
88-
let extension = path.extension().and_then(|s| s.to_str()).unwrap_or_default().to_lowercase();
89-
let Some(image_format) = image::ImageFormat::from_extension(&extension) else {
90-
tracing::warn!("Unsupported file type: {}", path.display());
91-
return;
92-
};
93-
let reader = image::ImageReader::with_format(std::io::Cursor::new(content), image_format);
94-
let Ok(image) = reader.decode() else {
95-
tracing::error!("Failed to decode image: {}", path.display());
96-
return;
97-
};
98-
let width = image.width();
99-
let height = image.height();
100-
101-
// TODO: Handle Image formats with more than 8 bits per channel
102-
let image_data = image.to_rgba8();
103-
let image = Image::<Color>::from_image_data(image_data.as_raw(), width, height);
104-
let message = PortfolioMessage::PasteImage {
105-
name,
106-
image,
107-
mouse: None,
108-
parent_and_insert_index: None,
109-
};
40+
let message = PortfolioMessage::ImportFile { path, content };
11041
dispatcher.queue_editor_message(message);
11142
}
11243
DesktopWrapperMessage::PollNodeGraphEvaluation => dispatcher.poll_node_graph_evaluation(),

desktop/wrapper/src/intercept_frontend_message.rs

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,17 @@ pub(super) fn intercept_frontend_message(dispatcher: &mut DesktopWrapperMessageD
1010
FrontendMessage::RenderOverlays { context } => {
1111
dispatcher.respond(DesktopFrontendMessage::UpdateOverlays(context.take_scene()));
1212
}
13-
FrontendMessage::TriggerOpenDocument => {
13+
FrontendMessage::TriggerOpen => {
1414
dispatcher.respond(DesktopFrontendMessage::OpenFileDialog {
1515
title: "Open Document".to_string(),
16-
filters: vec![FileFilter {
17-
name: "Graphite".to_string(),
18-
extensions: vec!["graphite".to_string()],
19-
}],
20-
context: OpenFileDialogContext::Document,
16+
filters: vec![],
17+
context: OpenFileDialogContext::Open,
2118
});
2219
}
2320
FrontendMessage::TriggerImport => {
2421
dispatcher.respond(DesktopFrontendMessage::OpenFileDialog {
2522
title: "Import File".to_string(),
26-
filters: vec![
27-
FileFilter {
28-
name: "Svg".to_string(),
29-
extensions: vec!["svg".to_string()],
30-
},
31-
FileFilter {
32-
name: "Image".to_string(),
33-
extensions: vec!["png".to_string(), "jpg".to_string(), "jpeg".to_string(), "bmp".to_string()],
34-
},
35-
],
23+
filters: vec![],
3624
context: OpenFileDialogContext::Import,
3725
});
3826
}

desktop/wrapper/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use graph_craft::wasm_application_io::WasmApplicationIo;
22
use graphite_editor::application::{Editor, Environment, Host, Platform};
33
use graphite_editor::messages::prelude::{FrontendMessage, Message};
44

5+
pub use graphite_editor::consts::FILE_EXTENSION;
56
// TODO: Remove usage of this reexport in desktop create and remove this line
67
pub use graphene_std::Color;
78

desktop/wrapper/src/messages.rs

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ pub enum DesktopFrontendMessage {
7979
pub enum DesktopWrapperMessage {
8080
FromWeb(Box<EditorMessage>),
8181
Input(InputMessage),
82-
OpenFileDialogResult {
82+
FileDialogResult {
8383
path: PathBuf,
8484
content: Vec<u8>,
8585
context: OpenFileDialogContext,
@@ -88,10 +88,6 @@ pub enum DesktopWrapperMessage {
8888
path: PathBuf,
8989
context: SaveFileDialogContext,
9090
},
91-
OpenDocument {
92-
path: PathBuf,
93-
content: Vec<u8>,
94-
},
9591
OpenFile {
9692
path: PathBuf,
9793
content: Vec<u8>,
@@ -100,14 +96,6 @@ pub enum DesktopWrapperMessage {
10096
path: PathBuf,
10197
content: Vec<u8>,
10298
},
103-
ImportSvg {
104-
path: PathBuf,
105-
content: Vec<u8>,
106-
},
107-
ImportImage {
108-
path: PathBuf,
109-
content: Vec<u8>,
110-
},
11199
PollNodeGraphEvaluation,
112100
UpdateMaximized {
113101
maximized: bool,
@@ -153,7 +141,7 @@ pub struct FileFilter {
153141
}
154142

155143
pub enum OpenFileDialogContext {
156-
Document,
144+
Open,
157145
Import,
158146
}
159147

editor/src/dispatcher.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -571,10 +571,9 @@ mod test {
571571
"Demo artwork '{document_name}' has more than 1 line (remember to open and re-save it in Graphite)",
572572
);
573573

574-
let responses = editor.editor.handle_message(PortfolioMessage::OpenDocumentFile {
575-
document_name: Some(document_name.to_string()),
576-
document_path: None,
577-
document_serialized_content,
574+
let responses = editor.editor.handle_message(PortfolioMessage::OpenFile {
575+
path: file_name.into(),
576+
content: document_serialized_content.bytes().collect(),
578577
});
579578

580579
// Check if the graph renders

editor/src/messages/frontend/frontend_message.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ pub enum FrontendMessage {
107107
font: Font,
108108
url: String,
109109
},
110-
TriggerImport,
111110
TriggerPersistenceRemoveDocument {
112111
#[serde(rename = "documentId")]
113112
document_id: DocumentId,
@@ -122,7 +121,8 @@ pub enum FrontendMessage {
122121
TriggerLoadRestAutoSaveDocuments,
123122
TriggerOpenLaunchDocuments,
124123
TriggerLoadPreferences,
125-
TriggerOpenDocument,
124+
TriggerOpen,
125+
TriggerImport,
126126
TriggerSavePreferences {
127127
preferences: PreferencesMessageHandler,
128128
},

editor/src/messages/input_mapper/input_mappings.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ pub fn input_mappings(zoom_with_scroll: bool) -> Mapping {
442442
entry!(KeyDown(Tab); modifiers=[Control, Shift], action_dispatch=PortfolioMessage::PrevDocument),
443443
entry!(KeyDown(KeyW); modifiers=[Accel], action_dispatch=PortfolioMessage::CloseActiveDocumentWithConfirmation),
444444
entry!(KeyDown(KeyW); modifiers=[Accel, Alt], action_dispatch=PortfolioMessage::CloseAllDocumentsWithConfirmation),
445-
entry!(KeyDown(KeyO); modifiers=[Accel], action_dispatch=PortfolioMessage::OpenDocument),
445+
entry!(KeyDown(KeyO); modifiers=[Accel], action_dispatch=PortfolioMessage::Open),
446446
entry!(KeyDown(KeyI); modifiers=[Accel], action_dispatch=PortfolioMessage::Import),
447447
entry!(KeyDown(KeyX); modifiers=[Accel], action_dispatch=PortfolioMessage::Cut { clipboard: Clipboard::Device }),
448448
entry!(KeyDown(KeyC); modifiers=[Accel], action_dispatch=PortfolioMessage::Copy { clipboard: Clipboard::Device }),

editor/src/messages/menu_bar/menu_bar_message_handler.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ impl LayoutHolder for MenuBarMessageHandler {
120120
MenuListEntry::new("Open…")
121121
.label("Open…")
122122
.icon("Folder")
123-
.tooltip_shortcut(action_shortcut!(PortfolioMessageDiscriminant::OpenDocument))
124-
.on_commit(|_| PortfolioMessage::OpenDocument.into()),
123+
.tooltip_shortcut(action_shortcut!(PortfolioMessageDiscriminant::Open))
124+
.on_commit(|_| PortfolioMessage::Open.into()),
125125
MenuListEntry::new("Open Demo Artwork…")
126126
.label("Open Demo Artwork…")
127127
.icon("Image")
@@ -161,7 +161,8 @@ impl LayoutHolder for MenuBarMessageHandler {
161161
.label("Import…")
162162
.icon("FileImport")
163163
.tooltip_shortcut(action_shortcut!(PortfolioMessageDiscriminant::Import))
164-
.on_commit(|_| PortfolioMessage::Import.into()),
164+
.on_commit(|_| PortfolioMessage::Import.into())
165+
.disabled(no_active_document),
165166
MenuListEntry::new("Export…")
166167
.label("Export…")
167168
.icon("FileExport")

0 commit comments

Comments
 (0)