From f97558cb68972370b242e4b2de273848d68e9299 Mon Sep 17 00:00:00 2001 From: Sophie Herold Date: Thu, 6 Aug 2026 13:47:39 +0200 Subject: [PATCH] image_view: Handle target file gone correctly Before, if the target file was gone, files_around just returned an empty list of files, leading Loupe to think there are no images and showing the empty state view. This was frequently triggered by the "Replace original" function in editing, since the tmp file was already gone, when the view moved to it. Now, the correct error is shown, and scrolling to the other files is possible. Issue #585 --- build-aux/flatpak/org.gnome.Loupe.Devel.json | 2 +- src/file_model.rs | 18 +++++++++++++----- src/metadata.rs | 3 +-- src/widgets/image_page.rs | 2 +- src/widgets/image_view.rs | 4 ++++ src/widgets/print.rs | 3 +-- 6 files changed, 21 insertions(+), 11 deletions(-) diff --git a/build-aux/flatpak/org.gnome.Loupe.Devel.json b/build-aux/flatpak/org.gnome.Loupe.Devel.json index eaede82..bed52d6 100644 --- a/build-aux/flatpak/org.gnome.Loupe.Devel.json +++ b/build-aux/flatpak/org.gnome.Loupe.Devel.json @@ -107,7 +107,7 @@ { "type": "git", "url": "https://gitlab.gnome.org/GNOME/glycin.git", - "commit": "b918acf0e6f9da4c051cad809f3c147678a93ab9" + "commit": "109bfc711ed6625e4206d4dbef56219cba5a5a88" } ] }, diff --git a/src/file_model.rs b/src/file_model.rs index 93a7a83..b8b0632 100644 --- a/src/file_model.rs +++ b/src/file_model.rs @@ -316,22 +316,30 @@ impl LpFileModel { } /// Returns `n` elements before and after given file - pub fn files_around(&self, file: &gio::File, n: usize) -> IndexMap { + pub fn files_around( + &self, + file: &gio::File, + n: usize, + ) -> Result, ()> { let Some(index) = self.index_of(file) else { - tracing::error!("URI not in model: {}", file.uri()); - return IndexMap::new(); + // This can happen when the file is deleted the moment the view moves to it. + // This frequently happens when the "Replace original" function is used in + // editing. + tracing::info!("URI not in model: {}", file.uri()); + return Err(()); }; let reduce = n.saturating_sub(index); - self.imp() + Ok(self + .imp() .files .borrow() .iter() .skip(index.saturating_sub(n)) .take(2 * n + 1 - reduce) .map(|(k, v)| (k.clone(), v.file.clone())) - .collect() + .collect()) } /// Return first file diff --git a/src/metadata.rs b/src/metadata.rs index 207941a..21670e4 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -28,10 +28,9 @@ use chrono::prelude::*; pub use file::FileInfo; use glib::TimeZone; use glycin::{Frame, FrameDetails, ImageDetails, MemoryFormat}; -use gufo::common::cicp; use gufo::common::datetime::DateTime; use gufo::common::orientation::Orientation; -use gufo::common::physical_dimension; +use gufo::common::{cicp, physical_dimension}; use crate::deps::*; use crate::util; diff --git a/src/widgets/image_page.rs b/src/widgets/image_page.rs index eb00471..507532b 100644 --- a/src/widgets/image_page.rs +++ b/src/widgets/image_page.rs @@ -128,7 +128,7 @@ mod imp { obj, move |_| { if obj.image().is_loaded() { - tracing::debug!("Showing image"); + tracing::debug!("Revealing image"); obj.imp() .stack .set_visible_child(&*obj.imp().image_stack_page); diff --git a/src/widgets/image_view.rs b/src/widgets/image_view.rs index 90f63b1..b16a599 100644 --- a/src/widgets/image_view.rs +++ b/src/widgets/image_view.rs @@ -610,6 +610,10 @@ impl LpImageView { let existing = sliding_view.pages(); let target = self.model().files_around(current_file, BUFFER); + let Ok(target) = target else { + return; + }; + // remove old pages for (uri, page) in &existing { if !target.contains_key(uri) { diff --git a/src/widgets/print.rs b/src/widgets/print.rs index 0f2f902..1ef9a75 100644 --- a/src/widgets/print.rs +++ b/src/widgets/print.rs @@ -201,9 +201,8 @@ impl Unit { } mod imp { - use crate::util; - use super::*; + use crate::util; #[derive(Debug, Default, CompositeTemplate, Properties)] #[template(file = "print.ui")]