From 775e5155bbff9a01acbd6da09da2dfe87be708dc Mon Sep 17 00:00:00 2001 From: bherbruck Date: Wed, 21 Oct 2026 10:52:08 -0400 Subject: [PATCH] Main green: revert the start page change (#4295) and fix the format 28 test (#4335) * Revert "Start page: sample pictures and the existence check of recent files run off the window thread (#4295)" This reverts commit d9059d8da506fb43844bef1e69544fb2c78e9890. * Test: an older design is marked format 28 now that 0.18.3 folded face pieces into 29 Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Claude Opus 5.5 --- crates/engine/src/naming_history_tests.rs | 2 + crates/ui-egui/src/home.rs | 77 +++-------------------- 2 files changed, 10 insertions(+), 69 deletions(-) diff --git a/crates/engine/src/naming_history_tests.rs b/crates/engine/src/naming_history_tests.rs index 2996ebe359..3a435a6ace 100644 --- a/crates/engine/src/naming_history_tests.rs +++ b/crates/engine/src/naming_history_tests.rs @@ -444,6 +444,8 @@ fn a_design_saved_before_pieces_were_numbered_by_place_keeps_their_numbers() { if let Some(Value::Array(pending)) = file.get_mut("format_pending") { pending.retain(|c| c != "face-pieces-by-place"); } + // 0.18.3 folded the change into format 29, so a build before it wrote 28. + file["format"] = Value::String(solidcraft_doc::format::format_string(28)); let old = solidcraft_doc::Document::from_json(&file.to_string()).unwrap(); assert!(old.features.iter().all(|f| f.kernel_piece_order), "the features of an older design keep the old numbering"); let mut reopened = Session::new(old); diff --git a/crates/ui-egui/src/home.rs b/crates/ui-egui/src/home.rs index 6c029c01b1..3dc2cd8cde 100644 --- a/crates/ui-egui/src/home.rs +++ b/crates/ui-egui/src/home.rs @@ -47,13 +47,6 @@ pub struct HomeState { remembering: Option>, /// A sample picked before its design was ready. wanted: Option, - /// Whether each recent file is there, found off the window thread (a stat of a slow or - /// disconnected drive must not hold up the page); unknown counts as there. - present: HashMap, - #[cfg(not(target_arch = "wasm32"))] - present_asked: std::collections::HashSet, - #[cfg(not(target_arch = "wasm32"))] - present_rx: Vec>, } impl HomeState { @@ -267,10 +260,6 @@ fn make(key: &str) -> Made { fn read_pictures(keys: Vec, tx: &std::sync::mpsc::Sender) -> Option> { let mut cold = Vec::new(); for key in keys { - if let Some(i) = key.strip_prefix("samplepic:").and_then(|i| i.parse::().ok()) { - tx.send((format!("sample:{i}"), sample_picture(i), None)).ok()?; - continue; - } match std::panic::catch_unwind(|| picture(&key)).ok().flatten() { Some(img) => tx.send((key, Some(img), None)).ok()?, None => cold.push(key), @@ -438,7 +427,7 @@ pub fn open_sample(app: &mut SolveApp, i: usize) { /// Is this recent design there to open: in memory, or something the host can bring back? pub fn available(app: &SolveApp, path: &str) -> bool { - app.home.present.get(path).copied().unwrap_or(true) || app.services.can_restore.as_ref().is_some_and(|can| can(path)) + solidcraft_engine::io::vfs::exists(path) || app.services.can_restore.as_ref().is_some_and(|can| can(path)) } pub fn open_recent(app: &mut SolveApp, path: &str) { @@ -454,39 +443,6 @@ pub fn open_recent(app: &mut SolveApp, path: &str) { app.open_path_async(path); } -/// Find out whether the recent files are there: on a thread, so the page never waits on a drive. -fn ask_present(h: &mut HomeState, ctx: &egui::Context, recent: &[String]) { - #[cfg(not(target_arch = "wasm32"))] - { - let new: Vec = recent.iter().filter(|p| h.present_asked.insert((*p).clone())).cloned().collect(); - if !new.is_empty() { - let (tx, rx) = std::sync::mpsc::channel(); - let ctx = ctx.clone(); - let spawned = std::thread::Builder::new().name("recent-files".into()).spawn(move || { - for p in new { - let there = solidcraft_engine::io::vfs::exists(&p); - if tx.send((p, there)).is_err() { - return; - } - ctx.request_repaint(); - } - }); - if spawned.is_ok() { - h.present_rx.push(rx); - } - } - for rx in &h.present_rx { - while let Ok((p, there)) = rx.try_recv() { - h.present.insert(p, there); - } - } - } - #[cfg(target_arch = "wasm32")] - for p in recent { - h.present.insert(p.clone(), solidcraft_engine::io::vfs::exists(p)); - } -} - /// The page itself (in place of the toolbar, browser and viewport). pub fn show(app: &mut SolveApp, ui: &mut egui::Ui) { poll(app, ui.ctx()); @@ -497,23 +453,12 @@ pub fn show(app: &mut SolveApp, ui: &mut egui::Ui) { for i in 0..samples.len() { let key = format!("sample:{i}"); if !app.home.thumbs.contains_key(&key) { - // Decoded on the thumbnail thread where there is one; the card shows its placeholder - // until the picture arrives. - #[cfg(not(target_arch = "wasm32"))] - { - app.home.queued.push(format!("samplepic:{i}")); - app.home.thumbs.insert(key, None); - } - #[cfg(target_arch = "wasm32")] install(&mut app.home, ui.ctx(), &key, sample_picture(i)); } } let recent = app.home.recent.clone(); - ask_present(&mut app.home, ui.ctx(), &recent); - for p in &recent { - if app.home.present.get(p).copied().unwrap_or(true) { - want(&mut app.home, p); - } + for p in recent.iter().filter(|p| solidcraft_engine::io::vfs::exists(p)) { + want(&mut app.home, p); } let mut action: Option> = None; egui::CentralPanel::default().frame(egui::Frame::NONE.fill(t.panel).inner_margin(egui::Margin::symmetric(36, 24))).show(ui, |ui| { @@ -772,9 +717,6 @@ mod tests { h.app.services.can_restore = Some(Box::new(|p| p.starts_with("/disk/known/"))); h.app.services.restore_file = Some(Box::new(move |p| sink.borrow_mut().push(p.to_string()))); assert!(available(&h.app, "/disk/known/Bracket.solidcraft")); - // A file is taken to be there until the background check says it is not. - assert!(available(&h.app, "/disk/other/Bracket.solidcraft")); - h.app.home.present.insert("/disk/other/Bracket.solidcraft".into(), false); assert!(!available(&h.app, "/disk/other/Bracket.solidcraft")); open_recent(&mut h.app, "/disk/known/Bracket.solidcraft"); assert_eq!(*asked.borrow(), ["/disk/known/Bracket.solidcraft"]); @@ -928,18 +870,15 @@ mod tests { } #[test] - fn first_home_frame_shows_placeholders_and_the_sample_pictures_arrive_without_building_any_model() { + fn first_home_frame_shows_all_samples_without_building_any_models() { let mut h = crate::scenario::Harness::new(); h.app.home.show(0); h.frames(1); - assert!(h.app.home.ready_samples() < solidcraft_engine::sample::samples().len(), "the first frame decodes nothing"); - let deadline = std::time::Instant::now() + std::time::Duration::from_secs(30); - while h.app.home.ready_samples() < solidcraft_engine::sample::samples().len() && std::time::Instant::now() < deadline { - std::thread::sleep(std::time::Duration::from_millis(10)); - h.frames(1); - } assert_eq!(h.app.home.ready_samples(), solidcraft_engine::sample::samples().len()); - assert!(h.app.home.samples.is_empty(), "no sample model was built"); + assert!(h.app.home.samples.is_empty()); + assert!(h.app.home.queued.is_empty()); + #[cfg(not(target_arch = "wasm32"))] + assert!(h.app.home.sample_rx.is_none() && h.app.home.rx.is_none()); } #[cfg(not(target_arch = "wasm32"))]