mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-24 10:37:03 -06:00
Merge PR #445 from MarekSpodBiedry: Info: keep a property draft when another field or the side menu is clicked (#422)
This commit is contained in:
@@ -353,6 +353,7 @@ pub fn show(app: &mut SlideApp, ui: &mut Ui) {
|
||||
}
|
||||
if nav_item(ui, *nav, &bs, index, &t).clicked() {
|
||||
bs.focus = None;
|
||||
commit_props(app, &bs);
|
||||
match act(app, *nav, bs.page) {
|
||||
None => out.close = true,
|
||||
Some(p) => out.page = Some(p),
|
||||
@@ -367,6 +368,7 @@ pub fn show(app: &mut SlideApp, ui: &mut Ui) {
|
||||
for (k, nav) in bottom.iter().enumerate().rev() {
|
||||
if nav_item(ui, *nav, &bs, first_bottom + k, &t).clicked() {
|
||||
bs.focus = None;
|
||||
commit_props(app, &bs);
|
||||
match act(app, *nav, bs.page) {
|
||||
None => out.close = true,
|
||||
Some(p) => out.page = Some(p),
|
||||
@@ -796,15 +798,16 @@ fn info(app: &mut SlideApp, ui: &mut Ui, bs: &mut Backstage) {
|
||||
let Some(draft) = bs.props.get_mut(i) else { continue };
|
||||
let l = ui.label(RichText::new(*label).color(t.text_dim));
|
||||
let id = ui.make_persistent_id(("backstage_prop", *key));
|
||||
// Show the presentation's value unless the field is being edited (undo…).
|
||||
if !ui.ctx().memory(|m| m.has_focus(id)) {
|
||||
draft.clone_from(&saved);
|
||||
}
|
||||
let resp = ui.add(egui::TextEdit::singleline(draft).id(id).hint_text(*hint).desired_width(300.0)).labelled_by(l.id);
|
||||
if resp.lost_focus() && *draft != saved {
|
||||
// Commit first: a click on another field takes the focus before this one is drawn.
|
||||
let mut p = serde_json::Map::new();
|
||||
p.insert((*key).to_string(), json!(draft.clone()));
|
||||
let _ = app.run("file.properties", Value::Object(p));
|
||||
} else if !resp.has_focus() && *draft != saved {
|
||||
// Show the presentation's value unless the field is being edited (undo...).
|
||||
draft.clone_from(&saved);
|
||||
ui.ctx().request_repaint();
|
||||
}
|
||||
ui.end_row();
|
||||
}
|
||||
@@ -814,6 +817,24 @@ fn info(app: &mut SlideApp, ui: &mut Ui, bs: &mut Backstage) {
|
||||
});
|
||||
}
|
||||
|
||||
/// Commits what the Info page's property fields hold and the presentation does not: a side-menu
|
||||
/// action such as Save runs before the field that is being left is drawn again (#422).
|
||||
fn commit_props(app: &mut SlideApp, bs: &Backstage) {
|
||||
if bs.page != Page::Info {
|
||||
return;
|
||||
}
|
||||
let Ok(v) = app.session.execute("file.info", &json!({})) else { return };
|
||||
let mut p = serde_json::Map::new();
|
||||
for ((key, _, _), draft) in PROPERTIES.iter().zip(&bs.props) {
|
||||
if v["properties"].get(*key).and_then(Value::as_str).unwrap_or("") != *draft {
|
||||
p.insert((*key).to_string(), json!(draft));
|
||||
}
|
||||
}
|
||||
if !p.is_empty() {
|
||||
let _ = app.run("file.properties", Value::Object(p));
|
||||
}
|
||||
}
|
||||
|
||||
/// `1234567` → `1.2 MB`.
|
||||
pub fn format_bytes(b: u64) -> String {
|
||||
match b {
|
||||
|
||||
@@ -347,6 +347,44 @@ fn info_shows_and_edits_the_properties() {
|
||||
assert!(h.state().backstage_open());
|
||||
}
|
||||
|
||||
/// Leaving a property field with a click on another field keeps what was typed.
|
||||
#[test]
|
||||
fn info_keeps_a_property_draft_when_another_field_is_clicked() {
|
||||
let mut h = harness(new_app());
|
||||
h.state_mut().run("app.backstage", json!({"page": "info"})).unwrap();
|
||||
h.run_steps(3);
|
||||
h.get_by_role_and_label(Role::TextInput, "Author").click();
|
||||
h.run_steps(2);
|
||||
h.get_by_role_and_label(Role::TextInput, "Author").type_text("Ada");
|
||||
h.run_steps(2);
|
||||
h.get_by_role_and_label(Role::TextInput, "Title").click();
|
||||
h.run_steps(4);
|
||||
assert_eq!(h.state().session.active().unwrap().doc.props.author, "Ada");
|
||||
}
|
||||
|
||||
/// Save straight from a property field saves what was typed (the side menu acts before the field
|
||||
/// is drawn again).
|
||||
#[test]
|
||||
fn info_saves_a_property_draft_when_save_is_clicked() {
|
||||
let dir = temp_dir("info-save");
|
||||
let path = dir.join("Draft.pptx").to_string_lossy().to_string();
|
||||
let mut s = Session::with_new();
|
||||
s.execute("file.saveAs", &json!({"path": path})).unwrap();
|
||||
let mut h = harness(SlideApp::new(s, Services::default()));
|
||||
h.state_mut().run("app.backstage", json!({"page": "info"})).unwrap();
|
||||
h.run_steps(3);
|
||||
h.get_by_role_and_label(Role::TextInput, "Author").click();
|
||||
h.run_steps(2);
|
||||
h.get_by_role_and_label(Role::TextInput, "Author").type_text("Ada");
|
||||
h.run_steps(2);
|
||||
click_nav(&h, "Save");
|
||||
h.run_steps(3);
|
||||
let doc = h.state().session.active().unwrap();
|
||||
assert_eq!(doc.doc.props.author, "Ada");
|
||||
assert!(!doc.is_dirty(), "the author went into the saved file");
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
/// With nothing open the File tab is the start screen: Home, New and Open, no back arrow, and Esc
|
||||
/// has nowhere to go.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user