diff options
author | Manos Pitsidianakis <el13635@mail.ntua.gr> | 2019-07-28 18:52:45 +0300 |
---|---|---|
committer | Manos Pitsidianakis <el13635@mail.ntua.gr> | 2019-07-28 20:15:41 +0300 |
commit | 8a0e702127bc6229cad363918ae7542b26c11317 (patch) | |
tree | 20dd37642c21e2d634c512496c33b2ca5761dce9 /ui | |
parent | 5b679be782e4930be393654c1a3095422bcf242e (diff) |
melib,ui: add MailboxEntry enum
Use an enum to describe a mailbox's state in ui::conf::Account instead
of Result.
Diffstat (limited to 'ui')
-rw-r--r-- | ui/src/components/mail/compose.rs | 2 | ||||
-rw-r--r-- | ui/src/components/mail/listing.rs | 10 | ||||
-rw-r--r-- | ui/src/components/mail/listing/compact.rs | 30 | ||||
-rw-r--r-- | ui/src/components/mail/listing/plain.rs | 7 | ||||
-rw-r--r-- | ui/src/components/mail/listing/thread.rs | 23 | ||||
-rw-r--r-- | ui/src/components/mail/view/thread.rs | 8 | ||||
-rw-r--r-- | ui/src/components/utilities.rs | 2 | ||||
-rw-r--r-- | ui/src/conf/accounts.rs | 166 | ||||
-rw-r--r-- | ui/src/state.rs | 9 |
9 files changed, 150 insertions, 107 deletions
diff --git a/ui/src/components/mail/compose.rs b/ui/src/components/mail/compose.rs index 573ade6d..b3db659e 100644 --- a/ui/src/components/mail/compose.rs +++ b/ui/src/components/mail/compose.rs @@ -143,7 +143,7 @@ impl Composer { context: &Context, ) -> Self { let account = &context.accounts[coordinates.0]; - let mailbox = &account[coordinates.1].as_ref().unwrap(); + let mailbox = &account[coordinates.1].unwrap(); let threads = &account.collection.threads[&mailbox.folder.hash()]; let thread_nodes = &threads.thread_nodes(); let mut ret = Composer::default(); diff --git a/ui/src/components/mail/listing.rs b/ui/src/components/mail/listing.rs index 8d44d380..fbb78c30 100644 --- a/ui/src/components/mail/listing.rs +++ b/ui/src/components/mail/listing.rs @@ -532,12 +532,16 @@ impl Listing { Ok(_) => { let account = &context.accounts[index]; let count = account[entries[&folder_idx].hash()] - .as_ref() .unwrap() .envelopes .iter() - .map(|h| &account.collection[&h]) - .filter(|e| !e.is_seen()) + .filter_map(|h| { + if account.collection[&h].is_seen() { + None + } else { + Some(()) + } + }) .count(); let len = s.len(); s.insert_str( diff --git a/ui/src/components/mail/listing/compact.rs b/ui/src/components/mail/listing/compact.rs index e3fa4023..68cb0bef 100644 --- a/ui/src/components/mail/listing/compact.rs +++ b/ui/src/components/mail/listing/compact.rs @@ -539,13 +539,14 @@ impl CompactListing { // Get mailbox as a reference. // match context.accounts[self.cursor_pos.0].status(folder_hash) { - Ok(_) => {} + Ok(()) => {} Err(_) => { + let message: String = context.accounts[self.cursor_pos.0][folder_hash].to_string(); self.data_columns.columns[0] = - CellBuffer::new("Loading.".len(), 1, Cell::with_char(' ')); + CellBuffer::new(message.len(), 1, Cell::with_char(' ')); self.length = 0; write_string_to_grid( - "Loading.", + message.as_str(), &mut self.data_columns.columns[0], Color::Default, Color::Default, @@ -562,7 +563,7 @@ impl CompactListing { } let account = &context.accounts[self.cursor_pos.0]; - let mailbox = account[self.cursor_pos.1].as_ref().unwrap(); + let mailbox = &account[self.cursor_pos.1].unwrap(); let threads = &account.collection.threads[&mailbox.folder.hash()]; self.order.clear(); @@ -778,7 +779,11 @@ impl CompactListing { return; } let account = &context.accounts[self.cursor_pos.0]; - let mailbox = account[self.cursor_pos.1].as_ref().unwrap(); + let mailbox = if account[self.cursor_pos.1].is_available() { + account[self.cursor_pos.1].unwrap() + } else { + return; + }; let threads = &account.collection.threads[&mailbox.folder.hash()]; self.length = 0; @@ -913,10 +918,7 @@ impl CompactListing { } fn get_envelope_under_cursor(&self, cursor: usize, context: &Context) -> EnvelopeHash { let account = &context.accounts[self.cursor_pos.0]; - let folder_hash = account[self.cursor_pos.1] - .as_ref() - .map(|m| m.folder.hash()) - .unwrap(); + let folder_hash = account[self.cursor_pos.1].unwrap().folder.hash(); let threads = &account.collection.threads[&folder_hash]; if self.filtered_selection.is_empty() { let thread_node = threads.root_set(cursor); @@ -1035,10 +1037,7 @@ impl Component for CompactListing { .thread() .clone() }; - let folder_hash = account[self.cursor_pos.1] - .as_ref() - .map(|m| m.folder.hash()) - .unwrap(); + let folder_hash = account[self.cursor_pos.1].unwrap().folder.hash(); let threads = &account.collection.threads[&folder_hash]; let root_thread_index = threads.root_iter().position(|t| t == thread_hash); if let Some(pos) = root_thread_index { @@ -1168,10 +1167,7 @@ impl Component for CompactListing { let i = self.get_envelope_under_cursor(self.cursor_pos.2, context); let account = &mut context.accounts[self.cursor_pos.0]; let thread_hash = account.get_env(&i).thread(); - let folder_hash = account[self.cursor_pos.1] - .as_ref() - .map(|m| m.folder.hash()) - .unwrap(); + let folder_hash = account[self.cursor_pos.1].unwrap().folder.hash(); let threads = account.collection.threads.entry(folder_hash).or_default(); let thread_group = threads.thread_nodes()[&thread_hash].thread_group(); let thread_group = threads.find(thread_group); diff --git a/ui/src/components/mail/listing/plain.rs b/ui/src/components/mail/listing/plain.rs index f045ba3a..df28ac71 100644 --- a/ui/src/components/mail/listing/plain.rs +++ b/ui/src/components/mail/listing/plain.rs @@ -266,10 +266,11 @@ impl PlainListing { match context.accounts[self.cursor_pos.0].status(folder_hash) { Ok(_) => {} Err(_) => { - self.content = CellBuffer::new(MAX_COLS, 1, Cell::with_char(' ')); + let message: String = context.accounts[self.cursor_pos.0][folder_hash].to_string(); + self.content = CellBuffer::new(message.len(), 1, Cell::with_char(' ')); self.length = 0; write_string_to_grid( - "Loading.", + message.as_str(), &mut self.content, Color::Default, Color::Default, @@ -280,7 +281,7 @@ impl PlainListing { } } let account = &context.accounts[self.cursor_pos.0]; - let mailbox = &account[self.cursor_pos.1].as_ref().unwrap(); + let mailbox = &account[self.cursor_pos.1].unwrap(); self.length = mailbox.len(); self.content = CellBuffer::new(MAX_COLS, self.length + 1, Cell::with_char(' ')); diff --git a/ui/src/components/mail/listing/thread.rs b/ui/src/components/mail/listing/thread.rs index af2682c9..de9537dd 100644 --- a/ui/src/components/mail/listing/thread.rs +++ b/ui/src/components/mail/listing/thread.rs @@ -137,9 +137,11 @@ impl ListingTrait for ThreadListing { } fn highlight_line(&mut self, grid: &mut CellBuffer, area: Area, idx: usize, context: &Context) { - let mailbox = &context.accounts[self.cursor_pos.0][self.cursor_pos.1] - .as_ref() - .unwrap(); + let mailbox = if context.accounts[self.cursor_pos.0][self.cursor_pos.1].is_available() { + context.accounts[self.cursor_pos.0][self.cursor_pos.1].unwrap() + } else { + return; + }; if mailbox.is_empty() || mailbox.len() <= idx { return; } @@ -222,10 +224,11 @@ impl ThreadListing { match context.accounts[self.cursor_pos.0].status(folder_hash) { Ok(_) => {} Err(_) => { - self.content = CellBuffer::new(MAX_COLS, 1, Cell::with_char(' ')); + let message: String = context.accounts[self.cursor_pos.0][folder_hash].to_string(); + self.content = CellBuffer::new(message.len(), 1, Cell::with_char(' ')); self.length = 0; write_string_to_grid( - "Loading.", + message.as_str(), &mut self.content, Color::Default, Color::Default, @@ -236,7 +239,7 @@ impl ThreadListing { } } let account = &context.accounts[self.cursor_pos.0]; - let mailbox = account[self.cursor_pos.1].as_ref().unwrap(); + let mailbox = account[self.cursor_pos.1].unwrap(); let threads = &account.collection.threads[&mailbox.folder.hash()]; self.length = threads.len(); @@ -328,9 +331,11 @@ impl ThreadListing { } fn highlight_line_self(&mut self, idx: usize, context: &Context) { - let mailbox = &context.accounts[self.cursor_pos.0][self.cursor_pos.1] - .as_ref() - .unwrap(); + let mailbox = if context.accounts[self.cursor_pos.0][self.cursor_pos.1].is_available() { + context.accounts[self.cursor_pos.0][self.cursor_pos.1].unwrap() + } else { + return; + }; if mailbox.is_empty() { return; } diff --git a/ui/src/components/mail/view/thread.rs b/ui/src/components/mail/view/thread.rs index ed6936bb..daf22102 100644 --- a/ui/src/components/mail/view/thread.rs +++ b/ui/src/components/mail/view/thread.rs @@ -158,7 +158,7 @@ impl ThreadView { fn initiate(&mut self, expanded_hash: Option<ThreadHash>, context: &Context) { /* stack to push thread messages in order in order to pop and print them later */ let account = &context.accounts[self.coordinates.0]; - let mailbox = &account[self.coordinates.1].as_ref().unwrap(); + let mailbox = &account[self.coordinates.1].unwrap(); let threads = &account.collection.threads[&mailbox.folder.hash()]; let thread_iter = threads.thread_iter(self.coordinates.2); @@ -607,7 +607,7 @@ impl ThreadView { /* First draw the thread subject on the first row */ let y = if self.dirty { let account = &context.accounts[self.coordinates.0]; - let mailbox = &account[self.coordinates.1].as_ref().unwrap(); + let mailbox = &account[self.coordinates.1].unwrap(); let threads = &account.collection.threads[&mailbox.folder.hash()]; let thread_node = &threads.thread_nodes()[&threads.root_set(self.coordinates.2)]; let i = if let Some(i) = thread_node.message() { @@ -688,7 +688,7 @@ impl ThreadView { /* First draw the thread subject on the first row */ let y = { let account = &context.accounts[self.coordinates.0]; - let mailbox = &account[self.coordinates.1].as_ref().unwrap(); + let mailbox = &account[self.coordinates.1].unwrap(); let threads = &account.collection.threads[&mailbox.folder.hash()]; let thread_node = &threads.thread_nodes()[&threads.root_set(self.coordinates.2)]; let i = if let Some(i) = thread_node.message() { @@ -904,7 +904,7 @@ impl Component for ThreadView { UIEvent::Input(Key::Char('e')) => { { let account = &context.accounts[self.coordinates.0]; - let mailbox = &account[self.coordinates.1].as_ref().unwrap(); + let mailbox = &account[self.coordinates.1].unwrap(); let threads = &account.collection.threads[&mailbox.folder.hash()]; let thread_node = &threads.thread_nodes()[&threads.root_set(self.coordinates.2)]; diff --git a/ui/src/components/utilities.rs b/ui/src/components/utilities.rs index 4b3d4cea..72b9e710 100644 --- a/ui/src/components/utilities.rs +++ b/ui/src/components/utilities.rs @@ -921,7 +921,7 @@ impl Component for StatusBar { } } let account = &context.accounts[*idx_a]; - let m = &account[*idx_f].as_ref().unwrap(); + let m = &account[*idx_f].unwrap(); self.status = format!( "{} | Mailbox: {}, Messages: {}, New: {}", self.mode, diff --git a/ui/src/conf/accounts.rs b/ui/src/conf/accounts.rs index fe2981ba..3bf8bd8a 100644 --- a/ui/src/conf/accounts.rs +++ b/ui/src/conf/accounts.rs @@ -46,24 +46,75 @@ use std::ops::{Index, IndexMut}; use std::result; use std::sync::Arc; -pub type Worker = Option<Async<(Result<FnvHashMap<EnvelopeHash, Envelope>>, Result<Mailbox>)>>; +pub type Worker = Option<Async<Result<(FnvHashMap<EnvelopeHash, Envelope>, Mailbox)>>>; macro_rules! mailbox { ($idx:expr, $folders:expr) => { - $folders - .get_mut(&$idx) - .unwrap() - .as_mut() - .unwrap() - .as_mut() - .unwrap() + $folders.get_mut(&$idx).unwrap().unwrap_mut() }; } +#[derive(Serialize, Debug)] +pub enum MailboxEntry { + Available(Mailbox), + Failed(MeliError), + /// first argument is done work, and second is total work + Parsing(usize, usize), + /// first argument is done work, and second is total work + Threading(usize, usize), +} + +impl std::fmt::Display for MailboxEntry { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "{}", + match self { + MailboxEntry::Available(ref m) => m.name().to_string(), + MailboxEntry::Failed(ref e) => e.to_string(), + MailboxEntry::Parsing(done, total) => { + format!("Parsing messages. [{}/{}]", done, total) + } + MailboxEntry::Threading(done, total) => { + format!("Calculating threads. [{}/{}]", done, total) + } + } + ) + } +} +impl MailboxEntry { + pub fn is_available(&self) -> bool { + if let MailboxEntry::Available(_) = self { + true + } else { + false + } + } + pub fn is_parsing(&self) -> bool { + if let MailboxEntry::Parsing(_, _) = self { + true + } else { + false + } + } + pub fn unwrap_mut(&mut self) -> &mut Mailbox { + match self { + MailboxEntry::Available(ref mut m) => m, + e => panic!(format!("mailbox is not available! {:#}", e)), + } + } + pub fn unwrap(&self) -> &Mailbox { + match self { + MailboxEntry::Available(ref m) => m, + e => panic!(format!("mailbox is not available! {:#}", e)), + } + } +} + #[derive(Debug)] pub struct Account { name: String, - pub(crate) folders: FnvHashMap<FolderHash, Option<Result<Mailbox>>>, + pub(crate) folders: FnvHashMap<FolderHash, MailboxEntry>, pub(crate) folders_order: Vec<FolderHash>, folder_names: FnvHashMap<FolderHash, String>, tree: Vec<FolderNode>, @@ -113,31 +164,21 @@ impl Drop for Account { pub struct MailboxIterator<'a> { folders_order: &'a [FolderHash], - folders: &'a FnvHashMap<FolderHash, Option<Result<Mailbox>>>, + folders: &'a FnvHashMap<FolderHash, MailboxEntry>, pos: usize, } impl<'a> Iterator for MailboxIterator<'a> { - type Item = Option<&'a Mailbox>; + type Item = &'a MailboxEntry; - fn next(&mut self) -> Option<Option<&'a Mailbox>> { + fn next(&mut self) -> Option<&'a MailboxEntry> { if self.pos == self.folders.len() { return None; } let fh = &self.folders_order[self.pos]; - if self.pos == self.folders.len() { - return None; - } - self.pos += 1; - if self.folders[&fh].is_none() { - return Some(None); - } - if let Some(Err(_)) = self.folders[&fh] { - return Some(None); - } - Some(Some(self.folders[&fh].as_ref().unwrap().as_ref().unwrap())) + Some(&self.folders[&fh]) } } @@ -156,7 +197,7 @@ impl Account { ) -> Self { let mut backend = map.get(settings.account().format())(settings.account()); let mut ref_folders: FnvHashMap<FolderHash, Folder> = backend.folders(); - let mut folders: FnvHashMap<FolderHash, Option<Result<Mailbox>>> = + let mut folders: FnvHashMap<FolderHash, MailboxEntry> = FnvHashMap::with_capacity_and_hasher(ref_folders.len(), Default::default()); let mut folders_order: Vec<FolderHash> = Vec::with_capacity(ref_folders.len()); let mut workers: FnvHashMap<FolderHash, Worker> = FnvHashMap::default(); @@ -208,7 +249,7 @@ impl Account { } } } - folders.insert(*h, None); + folders.insert(*h, MailboxEntry::Parsing(0, 0)); workers.insert( *h, Account::new_worker(f.clone(), &mut backend, notify_fn.clone()), @@ -282,15 +323,19 @@ impl Account { .collect::<FnvHashMap<EnvelopeHash, Envelope>>() }); let hash = folder.hash(); - let m = Mailbox::new(folder, envelopes.as_ref().map_err(Clone::clone)); - tx.send(AsyncStatus::Payload((envelopes, m))); + if envelopes.is_err() { + tx.send(AsyncStatus::Payload(Err(envelopes.unwrap_err()))); + notify_fn.notify(hash); + return; + } + let envelopes = envelopes.unwrap(); + let m = Mailbox::new(folder, &envelopes); + tx.send(AsyncStatus::Payload(Ok((envelopes, m)))); notify_fn.notify(hash); }))) } pub fn reload(&mut self, event: RefreshEvent, folder_hash: FolderHash) -> Option<UIEvent> { - if self.folders[&folder_hash].is_none() - || self.folders[&folder_hash].as_ref().unwrap().is_err() - { + if !self.folders[&folder_hash].is_available() { self.event_queue.push_back((folder_hash, event)); return None; } @@ -306,15 +351,13 @@ impl Account { } RefreshEventKind::Rename(old_hash, new_hash) => { debug!("rename {} to {}", old_hash, new_hash); - let mailbox = mailbox!(&folder_hash, self.folders); - mailbox.rename(old_hash, new_hash); + mailbox!(&folder_hash, self.folders).rename(old_hash, new_hash); self.collection.rename(old_hash, new_hash, folder_hash); return Some(EnvelopeRename(old_hash, new_hash)); } RefreshEventKind::Create(envelope) => { let env_hash = envelope.hash(); - let mailbox = mailbox!(&folder_hash, self.folders); - mailbox.insert(env_hash); + mailbox!(&folder_hash, self.folders).insert(env_hash); self.collection.insert(*envelope, folder_hash); if self .sent_folder @@ -367,7 +410,7 @@ impl Account { pub fn watch(&self, r: RefreshEventConsumer) { self.backend.watch(r).unwrap(); } - /* This doesn't represent the number of correctly parsed mailboxes though */ + pub fn len(&self) -> usize { self.folders.len() } @@ -417,17 +460,18 @@ impl Account { fn load_mailbox( &mut self, folder_hash: FolderHash, - mailbox: (Result<FnvHashMap<EnvelopeHash, Envelope>>, Result<Mailbox>), + payload: (Result<(FnvHashMap<EnvelopeHash, Envelope>, Mailbox)>), ) { - let (envs, mut mailbox) = mailbox; - if envs.is_err() { - self.folders.insert(folder_hash, None); + if payload.is_err() { + self.folders + .insert(folder_hash, MailboxEntry::Failed(payload.unwrap_err())); return; } - let envs = envs.unwrap(); + let (envelopes, mut mailbox) = payload.unwrap(); self.collection - .merge(envs, folder_hash, &mut mailbox, self.sent_folder); - self.folders.insert(folder_hash, Some(mailbox)); + .merge(envelopes, folder_hash, &mut mailbox, self.sent_folder); + self.folders + .insert(folder_hash, MailboxEntry::Available(mailbox)); } pub fn status(&mut self, folder_hash: FolderHash) -> result::Result<(), usize> { @@ -435,12 +479,17 @@ impl Account { None => { return Ok(()); } - Some(ref mut w) if self.folders[&folder_hash].is_none() => match w.poll() { + Some(ref mut w) if self.folders[&folder_hash].is_parsing() => match w.poll() { Ok(AsyncStatus::NoUpdate) => { return Err(0); } Ok(AsyncStatus::Finished) => {} Ok(AsyncStatus::ProgressReport(n)) => { + self.folders.entry(folder_hash).and_modify(|f| { + if let MailboxEntry::Parsing(ref mut d, _) = f { + *d += n; + } + }); return Err(n); } _ => { @@ -496,7 +545,7 @@ impl Account { } pub fn operation(&self, h: EnvelopeHash) -> Box<BackendOp> { for mailbox in self.folders.values() { - if let Some(Ok(m)) = mailbox { + if let MailboxEntry::Available(ref m) = mailbox { if m.envelopes.contains(&h) { let operation = self.backend.operation(h, m.folder.hash()); if self.settings.account.read_only() { @@ -542,41 +591,28 @@ impl Account { } impl Index<FolderHash> for Account { - type Output = Result<Mailbox>; - fn index(&self, index: FolderHash) -> &Result<Mailbox> { + type Output = MailboxEntry; + fn index(&self, index: FolderHash) -> &MailboxEntry { &self.folders[&index] - .as_ref() - .expect("BUG: Requested mailbox that is not yet available.") } } -/// Will panic if mailbox hasn't loaded, ask `status()` first. impl IndexMut<FolderHash> for Account { - fn index_mut(&mut self, index: FolderHash) -> &mut Result<Mailbox> { - self.folders - .get_mut(&index) - .unwrap() - .as_mut() - .expect("BUG: Requested mailbox that is not yet available.") + fn index_mut(&mut self, index: FolderHash) -> &mut MailboxEntry { + self.folders.get_mut(&index).unwrap() } } impl Index<usize> for Account { - type Output = Result<Mailbox>; - fn index(&self, index: usize) -> &Result<Mailbox> { + type Output = MailboxEntry; + fn index(&self, index: usize) -> &MailboxEntry { &self.folders[&self.folders_order[index]] - .as_ref() - .expect("BUG: Requested mailbox that is not yet available.") } } /// Will panic if mailbox hasn't loaded, ask `status()` first. impl IndexMut<usize> for Account { - fn index_mut(&mut self, index: usize) -> &mut Result<Mailbox> { - self.folders - .get_mut(&self.folders_order[index]) - .unwrap() - .as_mut() - .expect("BUG: Requested mailbox that is not yet available.") + fn index_mut(&mut self, index: usize) -> &mut MailboxEntry { + self.folders.get_mut(&self.folders_order[index]).unwrap() } } diff --git a/ui/src/state.rs b/ui/src/state.rs index a2c7602c..69b8b0f3 100644 --- a/ui/src/state.rs +++ b/ui/src/state.rs @@ -276,11 +276,12 @@ impl State { return; } if let Some(notification) = self.context.accounts[idxa].reload(event, hash) { + if let UIEvent::Notification(_, _) = notification { + self.context + .replies + .push_back(UIEvent::MailboxUpdate((idxa, hash))); + } self.rcv_event(notification); - } else { - self.context - .replies - .push_back(UIEvent::MailboxUpdate((idxa, hash))); } } else { debug!( |