diff --git a/meli/src/mail/listing.rs b/meli/src/mail/listing.rs index 1b3e41e1..55120322 100644 --- a/meli/src/mail/listing.rs +++ b/meli/src/mail/listing.rs @@ -39,6 +39,7 @@ use super::*; use crate::{ accounts::{JobRequest, MailboxStatus}, components::ExtendShortcutsMaps, + jobs::{JobId, JoinHandle}, }; pub const DEFAULT_ATTACHMENT_FLAG: &str = concat!("📎", emoji_text_presentation_selector!()); @@ -1006,6 +1007,37 @@ pub trait ListingTrait: Component { } } +#[derive(Debug)] +pub struct BackgroundSearch { + pub text: String, + pub timestamp: std::time::Instant, + pub handle: JoinHandle>>, +} + +impl From<(String, JoinHandle>>)> for BackgroundSearch { + fn from((text, handle): (String, JoinHandle>>)) -> Self { + Self { + text, + handle, + timestamp: std::time::Instant::now(), + } + } +} + +#[derive(Default, Debug)] +struct BackgroundJobs { + pub search_job: Option, + pub select_job: Option, +} + +impl BackgroundJobs { + pub fn is_match(&self, job_id: &JobId) -> bool { + [&self.search_job, &self.select_job].iter().any( + |bg| matches!(bg, Some(BackgroundSearch { handle, .. }) if handle.job_id == *job_id), + ) + } +} + #[derive(Debug)] pub enum ListingComponent { Compact(Box), diff --git a/meli/src/mail/listing/compact.rs b/meli/src/mail/listing/compact.rs index a1f8de81..1ee89622 100644 --- a/meli/src/mail/listing/compact.rs +++ b/meli/src/mail/listing/compact.rs @@ -142,10 +142,7 @@ pub struct CompactListing { rows_drawn: SegmentTree, rows: RowsState<(ThreadHash, EnvelopeHash)>, - #[allow(clippy::type_complexity)] - search_job: Option<(String, JoinHandle>>)>, - #[allow(clippy::type_complexity)] - select_job: Option<(String, JoinHandle>>)>, + bg_jobs: BackgroundJobs, filter_term: String, filtered_selection: Vec, filtered_order: HashMap, @@ -213,6 +210,7 @@ impl MailListingTrait for CompactListing { fn refresh_mailbox(&mut self, context: &mut Context, force: bool) { self.set_dirty(true); self.rows.clear(); + self.bg_jobs = BackgroundJobs::default(); let old_cursor_pos = self.cursor_pos; if !(self.cursor_pos.0 == self.new_cursor_pos.0 && self.cursor_pos.1 == self.new_cursor_pos.1) @@ -556,6 +554,7 @@ impl ListingTrait for CompactListing { fn set_coordinates(&mut self, coordinates: (AccountHash, MailboxHash)) { self.new_cursor_pos = (coordinates.0, coordinates.1, 0); self.focus = Focus::None; + self.bg_jobs = BackgroundJobs::default(); self.filtered_selection.clear(); self.filtered_order.clear(); self.filter_term.clear(); @@ -873,8 +872,7 @@ impl CompactListing { sort: (Default::default(), Default::default()), sortcmd: false, subsort: (SortField::Date, SortOrder::Desc), - search_job: None, - select_job: None, + bg_jobs: BackgroundJobs::default(), filter_term: String::new(), filtered_selection: Vec::new(), filtered_order: HashMap::default(), @@ -1524,9 +1522,9 @@ impl CompactListing { log::error!("{}", message); context.replies.push_back(UIEvent::Notification { title: Some("Could not perform search".into()), - source: None, body: message.into(), kind: Some(crate::types::NotificationType::Error(err.kind)), + source: Some(err), }); } } @@ -2030,14 +2028,14 @@ impl Component for CompactListing { .main_loop_handler .job_executor .spawn_specialized("search".into(), job); - self.search_job = Some((filter_term.to_string(), handle)); + self.bg_jobs.search_job = Some((filter_term.to_string(), handle).into()); } Err(err) => { context.replies.push_back(UIEvent::Notification { title: Some("Could not perform search".into()), - source: None, body: err.to_string().into(), kind: Some(crate::types::NotificationType::Error(err.kind)), + source: Some(err), }); } }; @@ -2058,15 +2056,16 @@ impl Component for CompactListing { if let Ok(Some(search_result)) = try_recv_timeout!(&mut handle.chan) { self.select(search_term, search_result, context); } else { - self.select_job = Some((search_term.to_string(), handle)); + self.bg_jobs.select_job = + Some((search_term.to_string(), handle).into()); } } Err(err) => { context.replies.push_back(UIEvent::Notification { title: Some("Could not perform search".into()), - source: None, body: err.to_string().into(), kind: Some(crate::types::NotificationType::Error(err.kind)), + source: Some(err), }); } }; @@ -2074,42 +2073,56 @@ impl Component for CompactListing { return true; } UIEvent::StatusEvent(StatusEvent::JobFinished(ref job_id)) - if self - .search_job - .as_ref() - .map(|(_, j)| j == job_id) - .unwrap_or(false) => + if self.bg_jobs.is_match(job_id) => { - let (filter_term, mut handle) = self.search_job.take().unwrap(); - match handle.chan.try_recv() { - Err(_) => { /* search was canceled */ } - Ok(None) => { /* something happened, perhaps a worker thread panicked */ } - Ok(Some(Ok(results))) => self.filter(filter_term, results, context), - Ok(Some(Err(err))) => { - context.replies.push_back(UIEvent::Notification { - title: Some("Could not perform search".into()), - source: None, - body: err.to_string().into(), - kind: Some(crate::types::NotificationType::Error(err.kind)), - }); + let job = self.bg_jobs.search_job.take(); + if job + .as_ref() + .map(|bg| bg.handle.job_id == *job_id) + .unwrap_or(false) + { + let BackgroundSearch { + text: filter_term, + mut handle, + .. + } = job.unwrap(); + match handle.chan.try_recv() { + Err(_) => { /* search was canceled */ } + Ok(None) => { /* something happened, perhaps a worker thread panicked */ } + Ok(Some(Ok(results))) => self.filter(filter_term, results, context), + Ok(Some(Err(err))) => { + context.replies.push_back(UIEvent::Notification { + title: Some("Could not perform search".into()), + body: err.to_string().into(), + kind: Some(crate::types::NotificationType::Error(err.kind)), + source: Some(err), + }); + } } + self.set_dirty(true); + return false; } - self.set_dirty(true); - } - UIEvent::StatusEvent(StatusEvent::JobFinished(ref job_id)) - if self - .select_job + self.bg_jobs.search_job = job; + let job = self.bg_jobs.select_job.take(); + if job .as_ref() - .map(|(_, j)| j == job_id) - .unwrap_or(false) => - { - let (search_term, mut handle) = self.select_job.take().unwrap(); - match handle.chan.try_recv() { - Err(_) => { /* search was canceled */ } - Ok(None) => { /* something happened, perhaps a worker thread panicked */ } - Ok(Some(results)) => self.select(&search_term, results, context), + .map(|bg| bg.handle.job_id == *job_id) + .unwrap_or(false) + { + let BackgroundSearch { + text: search_term, + mut handle, + .. + } = job.unwrap(); + match handle.chan.try_recv() { + Err(_) => { /* search was canceled */ } + Ok(None) => { /* something happened, perhaps a worker thread panicked */ } + Ok(Some(results)) => self.select(&search_term, results, context), + } + self.set_dirty(true); + return false; } - self.set_dirty(true); + self.bg_jobs.select_job = job; } _ => {} }