fix: data-safety fixes from the project review
- autosave: pages a failed flush could not write no longer end up in the notebook that is opened next; they go to the recovery folder - app: finish an open text edit and save before switching notebooks, and stay in the notebook when saving fails - trash: purge by the deletion time in the entry name, not by the folder's modification time, which survives the move into .trash - notebooks are identified by their folder name, so a copied folder is a notebook of its own instead of an alias of the original - manifest: fall back to manifest.json.bak only for a damaged file, not for a newer format version or an I/O error - strokes keep their width after scaling and a restart - PDF export draws shapes with their stroke width instead of a fixed 1.5 pt - a first page that fails to load shows the warning; a first page that was never saved is an empty page; make-space refuses read-only pages Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
1 parent
7c69edab12
commit
c2652ea05b
6 files changed
+540
-135
No files matched your search
+27
-1
@@ -691,6 +691,15 @@ impl Stroke {
|
||||
if let Some(ref mut shape) = self.shape {
|
||||
shape.scale(origin, factors);
|
||||
}
|
||||
// The line width grows with the stroke. It is stored and the mesh is rebuilt from it
|
||||
// on load; without this a scaled stroke would be back at its old width after a restart.
|
||||
// Images and text fields have no line width.
|
||||
if !self.is_object() {
|
||||
let factor = (factors.x * factors.y).abs().sqrt();
|
||||
if factor.is_finite() && factor > 0.0 {
|
||||
self.width *= factor;
|
||||
}
|
||||
}
|
||||
self.recompute_aabb();
|
||||
}
|
||||
|
||||
@@ -1574,7 +1583,12 @@ impl Notebook {
|
||||
/// der Seite und gibt die Kennungen der geänderten Seiten zurück (`None`: nichts zu tun).
|
||||
pub fn make_space(&mut self, page_index: usize, y: f32, dy: f32) -> Option<Vec<u64>> {
|
||||
let run = self.space_run(page_index)?;
|
||||
if self.pages[run.clone()].iter().any(|p| !p.is_loaded) {
|
||||
// A page that could not be loaded is never saved: strokes pushed onto it would be gone
|
||||
// after a restart, and its own content is unknown
|
||||
if self.pages[run.clone()]
|
||||
.iter()
|
||||
.any(|p| !p.is_loaded || p.is_readonly())
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let dy = if dy < 0.0 {
|
||||
@@ -2680,6 +2694,18 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_make_space_refuses_pages_that_failed_to_load() {
|
||||
let mut nb = Notebook::new();
|
||||
nb.add_page(PageBackground::Blank);
|
||||
nb.pages[0].strokes = vec![block(1, 1000.0, 100.0)];
|
||||
nb.pages[1].persist = PersistState::ReadOnlyAfterLoadError;
|
||||
assert!(nb.make_space(0, 900.0, 300.0).is_none());
|
||||
assert_eq!(top_of(&nb, 0, 1), Some(1000.0));
|
||||
nb.pages[1].persist = PersistState::Normal;
|
||||
assert!(nb.make_space(0, 900.0, 300.0).is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remove_and_restore_current_page() {
|
||||
let mut nb = Notebook::new();
|
||||
|
||||
Reference in new issue
Block a user