mirror of
https://github.com/storytold/figcraft.git
synced 2026-11-07 11:03:15 +00:00
figcraft-web: a Save of a host-opened document goes out under the host's file name
In page host mode a plain Save of a .figcraft the host opened used the document's internal name, so the host got a different file name with saveAs true instead of an update to the file it opened. Services gains host_file(); Save uses it for a .figcraft host file, Save As keeps the document name, and a missing, .json or .fig host file stays a Save As.
This commit is contained in:
1 parent
cb9a63807e
commit
05db36303f
6 files changed
+95
-6
No files matched your search
@@ -91,6 +91,11 @@ impl Bridge {
|
||||
let _ = self.host.post_failed(error, None);
|
||||
}
|
||||
|
||||
/// The document file the host opened or the last Save As made, if any.
|
||||
pub fn host_file(&self) -> Option<String> {
|
||||
self.host_file.borrow().clone()
|
||||
}
|
||||
|
||||
/// Hand a file the app would otherwise download to the host; `false` when nothing was
|
||||
/// delivered. The `saveAs` rule is this module's documentation's.
|
||||
pub fn post_save(&self, path: &str, bytes: &[u8]) -> bool {
|
||||
|
||||
@@ -279,6 +279,9 @@ impl Services for WebServices {
|
||||
}
|
||||
}
|
||||
}
|
||||
fn host_file(&self) -> Option<String> {
|
||||
self.host.as_ref()?.host_file()
|
||||
}
|
||||
fn clipboard_set_text(&mut self, s: &str) {
|
||||
figcraft_ui_egui::egui_copy_text(&self.ctx, s);
|
||||
}
|
||||
|
||||
@@ -6,12 +6,7 @@ use super::{
|
||||
impl FigApp {
|
||||
pub fn save_as_dialog(&mut self) {
|
||||
if self.services.downloads() {
|
||||
if let Some(r) = self.run("file.saveAs", json!({"data": true}))
|
||||
&& self.download(r["name"].as_str().unwrap_or_default(), &r)
|
||||
{
|
||||
self.run("file.markSaved", json!({}));
|
||||
dialogs::file_saved(self, &r);
|
||||
}
|
||||
self.save_download(None);
|
||||
return;
|
||||
}
|
||||
let Ok(name) = self.session.doc().map(|d| d.name.clone()) else { return };
|
||||
@@ -43,6 +38,17 @@ impl FigApp {
|
||||
});
|
||||
}
|
||||
|
||||
/// Save by handing the file over as a download. `keep`: the name a Save of a host-opened
|
||||
/// document keeps; `None` is a Save As, under the document's own name.
|
||||
fn save_download(&mut self, keep: Option<&str>) {
|
||||
if let Some(r) = self.run("file.saveAs", json!({"data": true}))
|
||||
&& self.download(keep.unwrap_or_else(|| r["name"].as_str().unwrap_or_default()), &r)
|
||||
{
|
||||
self.run("file.markSaved", json!({}));
|
||||
dialogs::file_saved(self, &r);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn save(&mut self) {
|
||||
// A branch tab saves its main file.
|
||||
let tab = figcraft_engine::branches::file_tab(&self.session);
|
||||
@@ -57,6 +63,9 @@ impl FigApp {
|
||||
if self.run("file.save", json!({})).is_some() {
|
||||
self.toast(i18n::tr("Saved"));
|
||||
}
|
||||
} else if let Some(name) = self.services.host_file().filter(|n| is_document_file(n)) {
|
||||
// A host-opened document is saved as the file the host gave: the host updates that file.
|
||||
self.save_download(Some(&name));
|
||||
} else {
|
||||
self.save_as_dialog();
|
||||
}
|
||||
@@ -299,3 +308,8 @@ impl FigApp {
|
||||
failed
|
||||
}
|
||||
}
|
||||
|
||||
/// A `.figcraft` file name: the document format a Save writes (a `.fig` is an export copy).
|
||||
fn is_document_file(name: &str) -> bool {
|
||||
Path::new(name).extension().and_then(OsStr::to_str).is_some_and(|e| e.eq_ignore_ascii_case("figcraft"))
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
//! In a page host the browser hands files to the host: a Save of the document the host opened goes
|
||||
//! out under the host's file name, a Save As under the document's own name.
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use figcraft_engine::Session;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::{FigApp, Services};
|
||||
|
||||
type Saved = Arc<Mutex<Vec<String>>>;
|
||||
|
||||
/// Services that save by downloads, with a document file the host opened.
|
||||
struct Host {
|
||||
got: Saved,
|
||||
file: Option<&'static str>,
|
||||
}
|
||||
|
||||
impl Services for Host {
|
||||
fn downloads(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn download(&mut self, name: &str, _bytes: &[u8]) -> bool {
|
||||
self.got.lock().unwrap().push(name.to_string());
|
||||
true
|
||||
}
|
||||
fn host_file(&self) -> Option<String> {
|
||||
self.file.map(str::to_string)
|
||||
}
|
||||
}
|
||||
|
||||
fn app(file: Option<&'static str>) -> (FigApp, Saved) {
|
||||
let got = Saved::default();
|
||||
let mut app = FigApp::new(Session::empty(), Box::new(Host { got: got.clone(), file }));
|
||||
app.session.execute("file.new", &json!({"name": "Original"})).unwrap();
|
||||
(app, got)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn save_keeps_the_name_the_host_opened() {
|
||||
let (mut app, got) = app(Some("client.figcraft"));
|
||||
app.save();
|
||||
assert_eq!(got.lock().unwrap().as_slice(), ["client.figcraft"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn save_as_uses_the_document_s_own_name() {
|
||||
let (mut app, got) = app(Some("client.figcraft"));
|
||||
app.save_as_dialog();
|
||||
assert_eq!(got.lock().unwrap().as_slice(), ["Original.figcraft"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn without_a_host_file_or_for_a_copy_format_save_is_a_save_as() {
|
||||
for file in [None, Some("design.json"), Some("export.fig")] {
|
||||
let (mut app, got) = app(file);
|
||||
app.save();
|
||||
assert_eq!(got.lock().unwrap().as_slice(), ["Original.figcraft"], "{file:?}");
|
||||
}
|
||||
}
|
||||
@@ -124,6 +124,8 @@ mod home_recents_tests;
|
||||
#[cfg(test)]
|
||||
mod home_tests;
|
||||
#[cfg(test)]
|
||||
mod host_save_tests;
|
||||
#[cfg(test)]
|
||||
mod idle_tests;
|
||||
#[cfg(test)]
|
||||
mod ime_tests;
|
||||
|
||||
@@ -24,6 +24,11 @@ pub trait Services {
|
||||
fn download(&mut self, _name: &str, _bytes: &[u8]) -> bool {
|
||||
false
|
||||
}
|
||||
/// The document file a host page opened, where the app runs inside one (the browser's host
|
||||
/// mode): a Save of that document keeps this name instead of the document's own.
|
||||
fn host_file(&self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
/// A folder to write several files into.
|
||||
fn pick_folder(&mut self, _title: &str) -> DialogFuture {
|
||||
Box::pin(std::future::ready(None))
|
||||
|
||||
Reference in new issue
Block a user