mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-04 11:05:56 +00:00
* Revert "Start page: sample pictures and the existence check of recent files run off the window thread (#4295)"
This reverts commit d9059d8da5.
* 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 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -47,13 +47,6 @@ pub struct HomeState {
|
||||
remembering: Option<std::sync::mpsc::Receiver<Made>>,
|
||||
/// A sample picked before its design was ready.
|
||||
wanted: Option<usize>,
|
||||
/// 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<String, bool>,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
present_asked: std::collections::HashSet<String>,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
present_rx: Vec<std::sync::mpsc::Receiver<(String, bool)>>,
|
||||
}
|
||||
|
||||
impl HomeState {
|
||||
@@ -267,10 +260,6 @@ fn make(key: &str) -> Made {
|
||||
fn read_pictures(keys: Vec<String>, tx: &std::sync::mpsc::Sender<Made>) -> Option<Vec<String>> {
|
||||
let mut cold = Vec::new();
|
||||
for key in keys {
|
||||
if let Some(i) = key.strip_prefix("samplepic:").and_then(|i| i.parse::<usize>().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<String> = 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<Box<dyn FnOnce(&mut SolveApp)>> = 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"))]
|
||||
|
||||
Reference in New Issue
Block a user