From d0a2a9262e8286cbe5a02e3ddaf9b06c0068429e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 20 Mar 2024 16:27:00 -0600 Subject: [PATCH] Optimization for reloading metadata --- src/app.rs | 47 +++++++++++++++++++++++++++++++++++++++++++---- src/dialog.rs | 42 +++++++++++++++++++++++++++++++++++++++--- src/tab.rs | 2 +- 3 files changed, 83 insertions(+), 8 deletions(-) diff --git a/src/app.rs b/src/app.rs index d5da42e..e186ffa 100644 --- a/src/app.rs +++ b/src/app.rs @@ -916,16 +916,55 @@ impl Application for App { log::debug!("{:?}", events); let mut needs_reload = Vec::new(); - for entity in self.tab_model.iter() { - if let Some(tab) = self.tab_model.data::(entity) { + let entities: Vec<_> = self.tab_model.iter().collect(); + for entity in entities { + if let Some(tab) = self.tab_model.data_mut::(entity) { //TODO: support reloading trash, somehow if let Location::Path(path) = &tab.location { let mut contains_change = false; for event in events.iter() { for event_path in event.paths.iter() { if event_path.starts_with(&path) { - contains_change = true; - break; + match event.kind { + notify::EventKind::Modify( + notify::event::ModifyKind::Metadata(_), + ) + | notify::EventKind::Modify( + notify::event::ModifyKind::Data(_), + ) => { + // If metadata or data changed, find the matching item and reload it + //TODO: this could be further optimized by looking at what exactly changed + if let Some(items) = &mut tab.items_opt { + for item in items.iter_mut() { + if item.path_opt.as_ref() + == Some(event_path) + { + //TODO: reload more, like mime types? + match fs::metadata(&event_path) { + Ok(new_metadata) => match &mut item + .metadata + { + ItemMetadata::Path { + metadata, + .. + } => *metadata = new_metadata, + _ => {} + }, + Err(err) => { + log::warn!("failed to reload metadata for {:?}: {}", path, err); + } + } + //TODO item.thumbnail_opt = + } + } + } + } + _ => { + // Any other events reload the whole tab + contains_change = true; + break; + } + } } } } diff --git a/src/dialog.rs b/src/dialog.rs index 956d98a..af9ff6f 100644 --- a/src/dialog.rs +++ b/src/dialog.rs @@ -33,7 +33,7 @@ use std::{ use crate::{ config::TabConfig, fl, home_dir, - tab::{self, Location, Tab}, + tab::{self, ItemMetadata, Location, Tab}, }; #[derive(Clone, Debug)] @@ -460,8 +460,44 @@ impl Application for App { for event in events.iter() { for event_path in event.paths.iter() { if event_path.starts_with(&path) { - contains_change = true; - break; + match event.kind { + notify::EventKind::Modify( + notify::event::ModifyKind::Metadata(_), + ) + | notify::EventKind::Modify(notify::event::ModifyKind::Data( + _, + )) => { + // If metadata or data changed, find the matching item and reload it + //TODO: this could be further optimized by looking at what exactly changed + if let Some(items) = &mut self.tab.items_opt { + for item in items.iter_mut() { + if item.path_opt.as_ref() == Some(event_path) { + //TODO: reload more, like mime types? + match fs::metadata(&event_path) { + Ok(new_metadata) => { + match &mut item.metadata { + ItemMetadata::Path { + metadata, + .. + } => *metadata = new_metadata, + _ => {} + } + } + Err(err) => { + log::warn!("failed to reload metadata for {:?}: {}", path, err); + } + } + //TODO item.thumbnail_opt = + } + } + } + } + _ => { + // Any other events reload the whole tab + contains_change = true; + break; + } + } } } } diff --git a/src/tab.rs b/src/tab.rs index ea8c69b..ff000e4 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -673,7 +673,7 @@ pub struct Tab { pub history_i: usize, pub history: Vec, pub config: TabConfig, - items_opt: Option>, + pub(crate) items_opt: Option>, scrollable_id: widget::Id, select_focus: Option, select_shift: Option,