ui: fix seen property of threads on open, add env rename events

embed
Manos Pitsidianakis 2019-04-01 23:53:06 +03:00
parent f36cb111b5
commit 11b2abd1d1
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
9 changed files with 105 additions and 21 deletions

View File

@ -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;
}
}

View File

@ -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<ThreadTree> = Vec::new();
thread_nodes[idx].len = thread_nodes[idx].children.len();

View File

@ -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,

View File

@ -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),

View File

@ -83,7 +83,33 @@ impl MailView {
coordinates: (usize, usize, EnvelopeHash),
pager: Option<Pager>,
subview: Option<Box<Component>>,
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;
}

View File

@ -585,6 +585,7 @@ impl Component for ThreadView {
),
None,
None,
context,
);
}

View File

@ -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<Async<Result<Mailbox>>>;
@ -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<Folder> = self.backend.folders();

View File

@ -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,

View File

@ -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<RefreshEvent>),
EnvelopeUpdate(EnvelopeHash),
EnvelopeRename(usize, EnvelopeHash, EnvelopeHash),
EnvelopeRemove(EnvelopeHash),
}
impl From<RefreshEvent> for UIEvent {