diff --git a/melib/src/mailbox/collection.rs b/melib/src/mailbox/collection.rs index 54ffaaa3a..9dffab4ba 100644 --- a/melib/src/mailbox/collection.rs +++ b/melib/src/mailbox/collection.rs @@ -107,7 +107,7 @@ impl Collection { env.set_hash(new_hash); self.envelopes.insert(new_hash, env); { - if self.threads.update_envelope(old_hash, new_hash).is_ok() { + if self.threads.update_envelope(old_hash, new_hash, &self.envelopes).is_ok() { return; } } @@ -123,7 +123,7 @@ impl Collection { let new_hash = envelope.hash(); self.envelopes.insert(new_hash, envelope); { - if self.threads.update_envelope(old_hash, new_hash).is_ok() { + if self.threads.update_envelope(old_hash, new_hash, &self.envelopes).is_ok() { return; } } diff --git a/melib/src/mailbox/thread.rs b/melib/src/mailbox/thread.rs index b4427b01a..8e86b842e 100644 --- a/melib/src/mailbox/thread.rs +++ b/melib/src/mailbox/thread.rs @@ -822,22 +822,26 @@ impl Threads { &mut self, old_hash: EnvelopeHash, new_hash: EnvelopeHash, + collection: &Envelopes, ) -> Result<(), ()> { /* must update: * - hash_set * - message fields in thread_nodes */ - self.hash_set.remove(&old_hash); - if let Some(node) = self + let idx = if let Some((idx, node)) = self .thread_nodes .iter_mut() - .find(|n| n.message.map(|n| n == old_hash).unwrap_or(false)) + .enumerate() + .find(|(_, n)| n.message.map(|n| n == old_hash).unwrap_or(false)) { node.message = Some(new_hash); + idx } else { return Err(()); - } + }; + self.hash_set.remove(&old_hash); self.hash_set.insert(new_hash); + self.rebuild_thread(idx, collection); Ok(()) } @@ -971,6 +975,26 @@ impl Threads { let mut node_idx = id; let mut stack = Vec::with_capacity(32); + let no_parent: bool = if let Some(node) = self.thread_nodes.get(node_idx) { + if node.parent.is_none() { + true + } else { + false + } + } else { + false + }; + + if no_parent { + let tree = self.tree.get_mut(); + if let Some(tree) = tree.iter_mut().find(|t| t.id == id) { + *tree = ThreadTree::new(id); + node_build(tree, id, &mut self.thread_nodes, 1, collection); + return; + } + unreachable!(); + } + /* Trace path back to root ThreadNode */ while let Some(p) = &self.thread_nodes[node_idx].parent { node_idx = *p; @@ -1310,7 +1334,7 @@ fn node_build( indentation + 1 }; - let mut has_unseen = thread_nodes[idx].has_unseen; + let mut has_unseen = !collection[&thread_nodes[idx].message.unwrap()].is_seen(); let mut child_vec: Vec = Vec::new(); thread_nodes[idx].len = thread_nodes[idx].children.len(); diff --git a/ui/src/components/mail/listing/plain.rs b/ui/src/components/mail/listing/plain.rs index d354aee34..ec3e23cb9 100644 --- a/ui/src/components/mail/listing/plain.rs +++ b/ui/src/components/mail/listing/plain.rs @@ -86,10 +86,12 @@ impl PlainListing { /// chosen. fn refresh_mailbox(&mut self, context: &mut Context) { self.dirty = true; - self.cursor_pos.2 = 0; - self.new_cursor_pos.2 = 0; - self.cursor_pos.1 = self.new_cursor_pos.1; - self.cursor_pos.0 = self.new_cursor_pos.0; + if !(self.cursor_pos.0 == self.new_cursor_pos.0 + && self.cursor_pos.1 == self.new_cursor_pos.1) + { + self.cursor_pos.2 = 0; + self.new_cursor_pos.2 = 0; + } // Inform State that we changed the current folder view. context.replies.push_back(UIEvent { @@ -98,13 +100,22 @@ impl PlainListing { }); // Get mailbox as a reference. // - loop { - // TODO: Show progress visually - if context.accounts[self.cursor_pos.0] - .status(self.cursor_pos.1) - .is_ok() - { - break; + // Get mailbox as a reference. + // + match context.accounts[self.cursor_pos.0].status(self.cursor_pos.1) { + Ok(_) => {} + Err(_) => { + self.content = CellBuffer::new(MAX_COLS, 1, Cell::with_char(' ')); + self.length = 0; + write_string_to_grid( + "Loading.", + &mut self.content, + Color::Default, + Color::Default, + ((0, 0), (MAX_COLS - 1, 0)), + false, + ); + return; } } let mailbox = &context.accounts[self.cursor_pos.0][self.cursor_pos.1] @@ -407,7 +418,7 @@ impl Component for PlainListing { coordinates.1, self.local_collection[self.cursor_pos.2], ); - self.view = Some(MailView::new(coordinates, None, None)); + self.view = Some(MailView::new(coordinates, None, None, context)); } self.view.as_mut().unwrap().draw( grid, diff --git a/ui/src/components/mail/listing/thread.rs b/ui/src/components/mail/listing/thread.rs index edfbd7dc0..4c909ae2a 100644 --- a/ui/src/components/mail/listing/thread.rs +++ b/ui/src/components/mail/listing/thread.rs @@ -546,7 +546,7 @@ impl Component for ThreadListing { self.locations[self.cursor_pos.2], ); - self.view = Some(MailView::new(coordinates, None, None)); + self.view = Some(MailView::new(coordinates, None, None, context)); self.view.as_mut().unwrap().draw( grid, (set_y(upper_left, mid + 1), bottom_right), diff --git a/ui/src/components/mail/view.rs b/ui/src/components/mail/view.rs index b8fd4b884..12602e336 100644 --- a/ui/src/components/mail/view.rs +++ b/ui/src/components/mail/view.rs @@ -83,7 +83,33 @@ impl MailView { coordinates: (usize, usize, EnvelopeHash), pager: Option, subview: Option>, + context: &mut Context, ) -> Self { + let account = &mut context.accounts[coordinates.0]; + let (hash, is_seen) = { + let mailbox = &mut account[coordinates.1].as_mut().unwrap(); + let envelope: &mut Envelope = &mut mailbox + .collection + .entry(coordinates.2) + .or_default(); + (envelope.hash(), envelope.is_seen()) + }; + if !is_seen { + let folder_hash = { + let mailbox = &mut account[coordinates.1].as_mut().unwrap(); + mailbox.folder.hash() + }; + let op = { + let backend = &account.backend; + backend.operation(hash, folder_hash) + }; + let mailbox = &mut account[coordinates.1].as_mut().unwrap(); + let envelope: &mut Envelope = &mut mailbox + .collection + .entry(coordinates.2) + .or_default(); + envelope.set_seen(op).unwrap(); + } MailView { coordinates, pager, @@ -220,6 +246,11 @@ impl Component for MailView { let mailbox = &mut accounts[self.coordinates.0][self.coordinates.1] .as_ref() .unwrap(); + if !mailbox.collection.contains_key(&self.coordinates.2) { + /* The envelope has been renamed or removed, so wait for the appropriate event to + * arrive */ + return; + } let envelope: &Envelope = &mailbox.collection[&self.coordinates.2]; if self.mode == ViewMode::Raw { @@ -620,6 +651,10 @@ impl Component for MailView { } self.dirty = true; } + UIEventType::EnvelopeRename(_, old_hash, new_hash) if old_hash == self.coordinates.2 => { + self.coordinates.2 = new_hash; + self.set_dirty(); + } _ => { return false; } diff --git a/ui/src/components/mail/view/thread.rs b/ui/src/components/mail/view/thread.rs index 62775e83c..577ea1b58 100644 --- a/ui/src/components/mail/view/thread.rs +++ b/ui/src/components/mail/view/thread.rs @@ -585,6 +585,7 @@ impl Component for ThreadView { ), None, None, + context, ); } diff --git a/ui/src/conf/accounts.rs b/ui/src/conf/accounts.rs index 9ac956cda..d739649c4 100644 --- a/ui/src/conf/accounts.rs +++ b/ui/src/conf/accounts.rs @@ -38,7 +38,7 @@ use std::mem; use std::ops::{Index, IndexMut}; use std::result; use std::sync::Arc; -use types::UIEventType::{self, Notification}; +use types::UIEventType::{self, Notification, EnvelopeUpdate, EnvelopeRename, EnvelopeRemove}; pub type Worker = Option>>; @@ -153,9 +153,14 @@ impl Account { match kind { RefreshEventKind::Update(old_hash, envelope) => { mailbox!(idx, self.folders).update(old_hash, *envelope); + return Some(EnvelopeUpdate(old_hash)); } RefreshEventKind::Rename(old_hash, new_hash) => { + if cfg!(feature = "debug_log") { + eprintln!("rename {} to {}", old_hash, new_hash); + } mailbox!(idx, self.folders).rename(old_hash, new_hash); + return Some(EnvelopeRename(idx, old_hash, new_hash)); } RefreshEventKind::Create(envelope) => { if cfg!(feature = "debug_log") { @@ -176,6 +181,7 @@ impl Account { } RefreshEventKind::Remove(envelope_hash) => { mailbox!(idx, self.folders).remove(envelope_hash); + return Some(EnvelopeRemove(envelope_hash)); } RefreshEventKind::Rescan => { let ref_folders: Vec = self.backend.folders(); diff --git a/ui/src/state.rs b/ui/src/state.rs index 320d3e2da..723693b14 100644 --- a/ui/src/state.rs +++ b/ui/src/state.rs @@ -280,6 +280,9 @@ impl State { self.context .sender .send(ThreadEvent::UIEvent(UIEventType::StartupCheck(hash))); + self.context + .sender + .send(ThreadEvent::UIEvent(UIEventType::MailboxUpdate((idxa, idxm)))); self.context.replies.push_back(UIEvent { id: 0, event_type: notification, diff --git a/ui/src/types.rs b/ui/src/types.rs index bbbbf547c..9f5b19baf 100644 --- a/ui/src/types.rs +++ b/ui/src/types.rs @@ -27,6 +27,7 @@ use super::execute::Action; use super::terminal::*; use melib::RefreshEvent; +use melib::EnvelopeHash; use melib::backends::FolderHash; use std; use std::fmt; @@ -86,6 +87,9 @@ pub enum UIEventType { EntityKill(Uuid), StartupCheck(FolderHash), RefreshEvent(Box), + EnvelopeUpdate(EnvelopeHash), + EnvelopeRename(usize, EnvelopeHash, EnvelopeHash), + EnvelopeRemove(EnvelopeHash), } impl From for UIEvent {