image: Refresh file info after file rename

This commit is contained in:
Sophie Herold 2023-12-04 17:19:33 +01:00
parent c0f435386d
commit 2fdfe5657c
5 changed files with 109 additions and 35 deletions

View file

@ -1,5 +1,5 @@
// Copyright (c) 2020-2022 Christopher Davis // Copyright (c) 2020-2022 Christopher Davis
// Copyright (c) 2022-2023 Sophie Herold // Copyright (c) 2023 Sophie Herold
// //
// This program is free software: you can redistribute it and/or modify // This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU General Public License as published by

View file

@ -1,3 +1,20 @@
// Copyright (c) 2023 Sophie Herold
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// SPDX-License-Identifier: GPL-3.0-or-later
use crate::deps::*; use crate::deps::*;
pub struct FileInfo { pub struct FileInfo {

View file

@ -1,3 +1,20 @@
// Copyright (c) 2023 Sophie Herold
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// SPDX-License-Identifier: GPL-3.0-or-later
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ImageFormat { pub struct ImageFormat {
mime_type: glycin::MimeType, mime_type: glycin::MimeType,

View file

@ -113,7 +113,7 @@ mod imp {
#[derive(Debug, Default, Properties)] #[derive(Debug, Default, Properties)]
#[properties(wrapper_type = super::LpImage)] #[properties(wrapper_type = super::LpImage)]
pub struct LpImage { pub struct LpImage {
#[property(get, set = LpImage::set_file, explicit_notify)] #[property(get, explicit_notify)]
pub(super) file: RefCell<Option<gio::File>>, pub(super) file: RefCell<Option<gio::File>>,
#[property(get)] #[property(get)]
pub(super) is_deleted: Cell<bool>, pub(super) is_deleted: Cell<bool>,
@ -520,28 +520,6 @@ mod imp {
zoom_gesture.group_with(&rotation_gesture); zoom_gesture.group_with(&rotation_gesture);
} }
fn set_file(&self, file: &gio::File) {
let obj = self.obj();
if obj.file().map_or(false, |x| file.equal(&x)) {
return;
}
self.file.replace(Some(file.clone()));
let monitor =
file.monitor_file(gio::FileMonitorFlags::WATCH_MOVES, gio::Cancellable::NONE);
if let Ok(m) = &monitor {
m.connect_changed(glib::clone!(@weak obj => move |_, file_a, file_b, event| {
obj.file_changed(event, file_a, file_b);
}));
}
self.file_monitor.replace(monitor.ok());
obj.notify_file();
}
fn set_mirrored(&self, mirrored: bool) { fn set_mirrored(&self, mirrored: bool) {
let obj = self.obj(); let obj = self.obj();
@ -813,20 +791,17 @@ glib::wrapper! {
} }
impl LpImage { impl LpImage {
pub fn init(&self, file: &gio::File) {
self.imp().file.replace(Some(file.clone()));
}
pub async fn load(&self, file: &gio::File) { pub async fn load(&self, file: &gio::File) {
let imp = self.imp(); let imp = self.imp();
log::debug!("Loading file {}", file.uri()); log::debug!("Loading file {}", file.uri());
self.set_file(file);
imp.metadata.replace(Metadata::default()); imp.metadata.replace(Metadata::default());
self.emmit_metadata_changed(); self.emmit_metadata_changed();
self.set_file_loaded(file).await;
let file_info = metadata::FileInfo::new(file).await;
match file_info {
Ok(file_info) => imp.metadata.borrow_mut().set_file_info(file_info),
Err(err) => log::warn!("Failed to load file information: {err}"),
}
self.emmit_metadata_changed();
let tiles = &self.imp().frame_buffer; let tiles = &self.imp().frame_buffer;
// Delete all stored textures for reloads // Delete all stored textures for reloads
@ -850,6 +825,68 @@ impl LpImage {
imp.decoder.replace(Some(Arc::new(decoder))); imp.decoder.replace(Some(Arc::new(decoder)));
} }
// Set filename when (re)loading image
async fn set_file_loaded(&self, file: &gio::File) {
let imp = self.imp();
// Do not check if same file since it might be set via initialized with `Self::init` before
imp.file.replace(Some(file.clone()));
self.reload_file_info().await;
self.setup_file_monitor().await;
self.notify_file();
}
/// Set filename after filename changed
async fn set_file_changed(&self, file: &gio::File) {
let imp = self.imp();
let prev_mime_type = self.metadata().mime_type();
imp.file.replace(Some(file.clone()));
self.reload_file_info().await;
// Reload if mime type changed since other decoding path might be responsible now
if self.metadata().mime_type() != prev_mime_type {
self.load(file).await;
return;
}
self.setup_file_monitor().await;
self.notify_file();
}
async fn reload_file_info(&self) {
let imp = self.imp();
if let Some(file) = self.file() {
let file_info = metadata::FileInfo::new(&file).await;
match file_info {
Ok(file_info) => imp.metadata.borrow_mut().set_file_info(file_info),
Err(err) => log::warn!("Failed to load file information: {err}"),
}
self.emmit_metadata_changed();
}
}
async fn setup_file_monitor(&self) {
let imp = self.imp();
if let Some(file) = self.file() {
let monitor =
file.monitor_file(gio::FileMonitorFlags::WATCH_MOVES, gio::Cancellable::NONE);
if let Ok(m) = &monitor {
m.connect_changed(
glib::clone!(@weak self as obj => move |_, file_a, file_b, event| {
obj.file_changed(event, file_a, file_b);
}),
);
}
imp.file_monitor.replace(monitor.ok());
}
}
/// Called when decoder sends update /// Called when decoder sends update
pub fn update(&self, update: DecoderUpdate) { pub fn update(&self, update: DecoderUpdate) {
let imp = self.imp(); let imp = self.imp();
@ -991,14 +1028,17 @@ impl LpImage {
log::debug!("Moved to {}", file.uri()); log::debug!("Moved to {}", file.uri());
// current file got replaced with a new one // current file got replaced with a new one
let file_replace = self.file().map_or(false, |x| x.equal(&file)); let file_replace = self.file().map_or(false, |x| x.equal(&file));
self.set_file(&file); let obj = self.clone();
if file_replace { if file_replace {
log::debug!("Image got replaced {}", file.uri()); log::debug!("Image got replaced {}", file.uri());
let obj = self.clone();
// TODO: error handling is missing // TODO: error handling is missing
glib::spawn_future_local(async move { glib::spawn_future_local(async move {
obj.load(&file).await; obj.load(&file).await;
}); });
} else {
glib::spawn_future_local(async move {
obj.set_file_changed(&file).await;
});
} }
} }
} }

View file

@ -153,7 +153,7 @@ impl LpImagePage {
pub fn from_file(file: &gio::File) -> Self { pub fn from_file(file: &gio::File) -> Self {
let obj = glib::Object::new::<Self>(); let obj = glib::Object::new::<Self>();
obj.imp().image.set_file(file); obj.imp().image.init(file);
glib::spawn_future_local(clone!(@weak obj, @strong file => async move { glib::spawn_future_local(clone!(@weak obj, @strong file => async move {
let imp = obj.imp(); let imp = obj.imp();