Skip to content

Commit f799ece

Browse files
gajopclaude
andcommitted
Notify on save, load, and import
Extend the native toast manager beyond export: Save posts "Project saved to <path>" so users have concrete reassurance it landed, Load confirms the opened project, diffuse import reports success or failure, and heightmap import (which runs as background IO) shows a progress toast that resolves to done or a warning. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 55340a9 commit f799ece

5 files changed

Lines changed: 46 additions & 4 deletions

File tree

‎native/src/sbc/heightmap/jobs/import.rs‎

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use log::error;
55
use crate::sbc::command_system::context::Context;
66
use crate::sbc::heightmap::ops::{import, read, write, Heightmap};
77
use crate::sbc::io::io_api::{IoJob, IoOutcome};
8+
use crate::sbc::notifications::NotificationManager;
89
use crate::sbc::sbc::SBC;
910

1011
/// Queues importing a grayscale PNG at `path` into the live heightmap, mapping
@@ -14,6 +15,8 @@ pub(crate) fn submit(ctx: &mut Context, path: PathBuf, min: f32, max: f32) {
1415
error!("import heightmap: could not read heightmap size");
1516
return;
1617
};
18+
ctx.model::<NotificationManager>()
19+
.progress("import", 0.2, "Importing heightmap...");
1720
ctx.submit_io(Box::new(ImportHeightmapJob {
1821
path,
1922
width,
@@ -50,8 +53,16 @@ enum ImportHeightmapOutcome {
5053
impl IoOutcome for ImportHeightmapOutcome {
5154
fn apply(self: Box<Self>, sbc: &mut SBC) {
5255
match *self {
53-
ImportHeightmapOutcome::Loaded(map) => write::write(sbc.interface(), &map),
54-
ImportHeightmapOutcome::Failed(reason) => error!("heightmap import failed: {reason}"),
56+
ImportHeightmapOutcome::Loaded(map) => {
57+
write::write(sbc.interface(), &map);
58+
sbc.model::<NotificationManager>()
59+
.progress("import", 1.0, "Heightmap imported");
60+
}
61+
ImportHeightmapOutcome::Failed(reason) => {
62+
error!("heightmap import failed: {reason}");
63+
sbc.model::<NotificationManager>()
64+
.warn("import", &format!("Heightmap import failed: {reason}"));
65+
}
5566
}
5667
}
5768
}

‎native/src/sbc/notifications/mod.rs‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ impl Model for NotificationManager {
3838
}
3939

4040
impl NotificationManager {
41+
/// Post or update a plain informational toast that auto-expires. Used for
42+
/// reassurance ("Project saved to …") rather than warnings or progress.
43+
pub(crate) fn info(&mut self, name: &str, title: &str, body: &str) {
44+
self.upsert(name, title, body, false, None, Some(Duration::from_secs(4)));
45+
}
46+
4147
/// Post or update a warning toast; it auto-expires after a few seconds.
4248
pub(crate) fn warn(&mut self, name: &str, body: &str) {
4349
self.upsert(

‎native/src/sbc/project/commands/load_project_command.rs‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use serde::Deserialize;
55
use crate::sbc::command_system::command::Command;
66
use crate::sbc::command_system::context::Context;
77
use crate::sbc::command_system::registry::register_command;
8+
use crate::sbc::notifications::NotificationManager;
89
use crate::sbc::project::io_registries::load;
910
use crate::sbc::project::ProjectManager;
1011

@@ -27,6 +28,11 @@ impl Command for LoadProjectCommand {
2728
.to_string();
2829
ctx.model::<ProjectManager>()
2930
.set_name_path(&name, &self.path);
31+
ctx.model::<NotificationManager>().info(
32+
"load",
33+
"Loaded",
34+
&format!("Opened project {name}"),
35+
);
3036
}
3137

3238
fn undoable(&self) -> bool {

‎native/src/sbc/project/commands/save_command.rs‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use serde::Deserialize;
55
use crate::sbc::command_system::command::Command;
66
use crate::sbc::command_system::context::Context;
77
use crate::sbc::command_system::registry::register_command;
8+
use crate::sbc::notifications::NotificationManager;
89
use crate::sbc::project::io_registries::save;
910
use crate::sbc::project::paths::ProjectPaths;
1011
use crate::sbc::project::ScreenshotManager;
@@ -36,6 +37,12 @@ impl Command for SaveCommand {
3637
// next DrawScreen write it.
3738
let path = ProjectPaths::new(&root).file(SCREENSHOT_FILE);
3839
ctx.model::<ScreenshotManager>().request(path);
40+
41+
ctx.model::<NotificationManager>().info(
42+
"save",
43+
"Saved",
44+
&format!("Project saved to {}", root.display()),
45+
);
3946
}
4047

4148
fn undoable(&self) -> bool {

‎native/src/sbc/textures/commands/import_diffuse_command.rs‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use serde::Deserialize;
66
use crate::sbc::command_system::command::Command;
77
use crate::sbc::command_system::context::Context;
88
use crate::sbc::command_system::registry::register_command;
9+
use crate::sbc::notifications::NotificationManager;
910
use crate::sbc::textures::model::TextureModel;
1011
use crate::sbc::textures::ops::import;
1112

@@ -26,8 +27,19 @@ impl Command for ImportDiffuseCommand {
2627
let path = PathBuf::from(&self.texture_path);
2728
let interface = *ctx.interface;
2829
match import::import_diffuse(&interface, ctx.model::<TextureModel>(), &path) {
29-
Ok(()) => info!("import diffuse: {}", path.display()),
30-
Err(err) => error!("import diffuse failed for {}: {err}", path.display()),
30+
Ok(()) => {
31+
info!("import diffuse: {}", path.display());
32+
ctx.model::<NotificationManager>().info(
33+
"import",
34+
"Imported",
35+
"Diffuse texture imported",
36+
);
37+
}
38+
Err(err) => {
39+
error!("import diffuse failed for {}: {err}", path.display());
40+
ctx.model::<NotificationManager>()
41+
.warn("import", &format!("Diffuse import failed: {err}"));
42+
}
3143
}
3244
}
3345

0 commit comments

Comments
 (0)