diff options
author | Manos Pitsidianakis <el13635@mail.ntua.gr> | 2018-10-14 19:49:16 +0300 |
---|---|---|
committer | Manos Pitsidianakis <el13635@mail.ntua.gr> | 2019-06-10 19:40:36 +0300 |
commit | 5a283200047f00d45d894b2873c583be7f00ad8b (patch) | |
tree | 536ff537b4cc26d96816e0ee70b9e2be9b214a5f /ui/src | |
parent | 21a918e4c0a20c2c7dce594979f4419e06ee16b1 (diff) |
WIP
Diffstat (limited to 'ui/src')
-rw-r--r-- | ui/src/components/indexer/index.rs | 187 | ||||
-rw-r--r-- | ui/src/components/indexer/mod.rs | 128 | ||||
-rw-r--r-- | ui/src/components/mail/listing/compact.rs | 29 | ||||
-rw-r--r-- | ui/src/components/mail/listing/mod.rs | 2 | ||||
-rw-r--r-- | ui/src/components/mail/listing/thread.rs | 272 | ||||
-rw-r--r-- | ui/src/components/mail/mod.rs | 3 | ||||
-rw-r--r-- | ui/src/components/mod.rs | 3 | ||||
-rw-r--r-- | ui/src/lib.rs | 3 | ||||
-rw-r--r-- | ui/src/state.rs | 34 | ||||
-rw-r--r-- | ui/src/types/accounts.rs | 75 | ||||
-rw-r--r-- | ui/src/types/cells.rs | 6 | ||||
-rw-r--r-- | ui/src/workers/mod.rs | 298 |
12 files changed, 883 insertions, 157 deletions
diff --git a/ui/src/components/indexer/index.rs b/ui/src/components/indexer/index.rs new file mode 100644 index 00000000..3faed023 --- /dev/null +++ b/ui/src/components/indexer/index.rs @@ -0,0 +1,187 @@ +use super::*; +use components::utilities::PageMovement; + +pub trait IndexContent: Component { + /* Handles the drawing of one entry */ + fn make_entry(&mut self, idx: usize) -> (); + + /* Handles what happens when the user selects an entry in the index listing */ + fn enter_entry(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) -> (); + + /* Refreshes content */ + fn refresh(&mut self, context: &mut Context) -> (); + + fn search(&self, term: &str) -> Option<usize>; +} + +#[derive(Debug, PartialEq)] +enum IndexState { + Uninitialized, + Listing, + Unfocused, + Search, +} + +#[derive(Debug)] +pub struct Index { + cursor_pos: usize, + new_cursor_pos: usize, + length: usize, + + /// Cache current view. + canvas: CellBuffer, + /// If we must redraw on next redraw event + dirty: bool, + state: IndexState, + + content: Box<IndexContent>, +} + +impl Index { + fn highlight_line(&self, grid: &mut CellBuffer, area: Area, idx: usize) { + let fg_color = Color::Default; + let bg_color = if self.cursor_pos == idx { + Color::Byte(246) + /* } else if idx % 2 == 0 { + Color::Byte(236)*/ + } else { + Color::Default + }; + change_colors(grid, area, fg_color, bg_color); + } +} + +impl Component for Index { + fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) { + if !self.dirty { + return; + } + + match self.state { + IndexState::Uninitialized => { + self.content.refresh(context); + + /* copy area */ + self.state = IndexState::Listing; + self.draw(grid, area, context); + return; + } + IndexState::Listing => { + /* rehighlight entries, redraw pages */ + let upper_left = upper_left!(area); + let bottom_right = bottom_right!(area); + let rows = get_y(bottom_right) - get_y(upper_left) + 1; + let prev_page_no = (self.cursor_pos).wrapping_div(rows); + let page_no = (self.new_cursor_pos).wrapping_div(rows); + + let top_idx = page_no * rows; + if self.new_cursor_pos >= self.length { + self.new_cursor_pos = self.length - 1; + } + /* If cursor position has changed, remove the highlight from the previous position and + * apply it in the new one. */ + if self.cursor_pos != self.new_cursor_pos && prev_page_no == page_no { + let old_cursor_pos = self.cursor_pos; + self.cursor_pos = self.new_cursor_pos; + for idx in &[old_cursor_pos, self.new_cursor_pos] { + if *idx >= self.length { + continue; //bounds check + } + let new_area = ( + set_y(upper_left, get_y(upper_left) + (*idx % rows)), + set_y(bottom_right, get_y(upper_left) + (*idx % rows)), + ); + self.highlight_line(grid, new_area, *idx); + context.dirty_areas.push_back(new_area); + } + return; + } else if self.cursor_pos != self.new_cursor_pos { + self.cursor_pos = self.new_cursor_pos; + } + + /* Page_no has changed, so draw new page */ + copy_area( + grid, + &self.canvas, + area, + ((0, top_idx), (500 - 1, self.length)), + ); + self.highlight_line( + grid, + ( + ( + get_x(upper_left), + get_y(upper_left) + (self.cursor_pos % rows), + ), + ( + get_x(bottom_right), + get_y(upper_left) + (self.cursor_pos % rows), + ), + ), + self.cursor_pos, + ); + context.dirty_areas.push_back(area); + } + IndexState::Unfocused => { + self.content.draw(grid, area, context); + } + IndexState::Search => unreachable!(), + } + + self.dirty = false; + return; + } + + fn process_event(&mut self, event: &UIEvent, context: &mut Context) -> bool { + if self.content.process_event(event, context) { + return true; + } + match event.event_type { + UIEventType::Input(Key::Up) => { + if self.cursor_pos > 0 { + self.new_cursor_pos = self.new_cursor_pos.saturating_sub(1); + self.set_dirty(); + } + return true; + } + UIEventType::Input(Key::Down) => { + if self.length > 0 && self.new_cursor_pos < self.length - 1 { + self.new_cursor_pos += 1; + self.set_dirty(); + } + return true; + } + UIEventType::Input(Key::Char('\n')) if self.state == IndexState::Listing => { + self.state = IndexState::Unfocused; + self.set_dirty(); + return true; + } + UIEventType::Input(Key::Char('i')) if self.state == IndexState::Unfocused => { + self.state = IndexState::Listing; + self.set_dirty(); + return true; + } + UIEventType::ChangeMode(UIMode::Normal) => { + self.set_dirty(); + } + UIEventType::Resize => { + self.set_dirty(); + } + _ => {} + } + + false + } + fn is_dirty(&self) -> bool { + self.dirty || self.content.is_dirty() + } + fn set_dirty(&mut self) { + self.dirty = true; + } +} + +impl fmt::Display for Index { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.content, f) + } +} diff --git a/ui/src/components/indexer/mod.rs b/ui/src/components/indexer/mod.rs new file mode 100644 index 00000000..078685bd --- /dev/null +++ b/ui/src/components/indexer/mod.rs @@ -0,0 +1,128 @@ +/* + * meli - ui crate. + * + * Copyright 2017-2018 Manos Pitsidianakis + * + * This file is part of meli. + * + * meli is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * meli is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with meli. If not, see <http://www.gnu.org/licenses/>. + */ + +/*! Entities that handle Mail specific functions. + */ +use super::*; + +pub mod index; +pub use self::index::*; + +#[derive(Debug)] +struct MenuEntry { + name: String, + subentries: Vec<MenuEntry>, + index: Index, +} + +#[derive(Debug)] +pub struct Indexer { + entries: Vec<MenuEntry>, + dirty: bool, + cursor: Vec<usize>, +} + +impl fmt::Display for Indexer { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // TODO display subject/info + write!(f, "index") + } +} + +impl Default for Indexer { + fn default() -> Self { + Indexer { + entries: Vec::with_capacity(8), + dirty: true, + cursor: Vec::with_capacity(8), + } + } +} + +impl Indexer { + fn draw_menu(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {} +} + +impl Component for Indexer { + fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) { + if !self.is_dirty() { + return; + } + + clear_area(grid, area); + let upper_left = upper_left!(area); + let bottom_right = bottom_right!(area); + + let total_cols = get_x(bottom_right) - get_x(upper_left); + let index_entity_width = (30 * total_cols) / 100; + let mid = get_x(bottom_right) - index_entity_width; + for i in get_y(upper_left)..=get_y(bottom_right) { + set_and_join_box(grid, (mid, i), VERT_BOUNDARY); + } + + let left_menu_area = (upper_left, (set_x(bottom_right, mid - 1))); + let right_index_area = (set_x(upper_left, mid + 1), bottom_right); + + self.draw_menu(grid, left_menu_area, context); + self.entries[self.cursor[0]] + .index + .draw(grid, right_index_area, context); + + self.dirty = false; + context.dirty_areas.push_back(area); + } + + fn process_event(&mut self, event: &UIEvent, _context: &mut Context) -> bool { + if !self.entries[self.cursor[0]] + .index + .process_event(event, _context) + { + for i in 0..self.entries.len() { + if i == self.cursor[0] { + continue; + } + self.entries[i].index.process_event(event, _context); + } + } + + match event.event_type { + UIEventType::RefreshMailbox(c) => { + self.dirty = true; + } + UIEventType::ChangeMode(UIMode::Normal) => { + self.dirty = true; + } + UIEventType::Resize => { + self.dirty = true; + } + _ => {} + } + false + } + + fn is_dirty(&self) -> bool { + self.dirty + } + + fn set_dirty(&mut self) { + self.dirty = true; + } +} diff --git a/ui/src/components/mail/listing/compact.rs b/ui/src/components/mail/listing/compact.rs index 3d339737..8814d30e 100644 --- a/ui/src/components/mail/listing/compact.rs +++ b/ui/src/components/mail/listing/compact.rs @@ -63,7 +63,7 @@ impl CompactListing { /// Helper function to format entry strings for CompactListing */ /* TODO: Make this configurable */ fn make_entry_string(e: &Envelope, len: usize, idx: usize) -> String { - if len > 1 { + if len > 0 { format!( "{} {} {:.85} ({})", idx, @@ -101,8 +101,13 @@ impl CompactListing { /// chosen. fn refresh_mailbox(&mut self, context: &mut Context) { self.dirty = true; - self.cursor_pos.2 = 0; - self.new_cursor_pos.2 = 0; + if !(self.cursor_pos.0 == self.new_cursor_pos.0 + && self.cursor_pos.1 == self.new_cursor_pos.1) + { + //TODO: store cursor_pos in each folder + 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; @@ -124,7 +129,7 @@ impl CompactListing { Color::Default, Color::Default, ((0, 0), (MAX_COLS - 1, 0)), - true, + false, ); return; } @@ -142,7 +147,7 @@ impl CompactListing { Color::Default, Color::Default, ((0, 0), (MAX_COLS - 1, 0)), - true, + false, ); return; } @@ -204,6 +209,9 @@ impl CompactListing { let mailbox = &context.accounts[self.cursor_pos.0][self.cursor_pos.1] .as_ref() .unwrap(); + if mailbox.len() == 0 { + return; + } let threads = &mailbox.collection.threads; let thread_node = threads.root_set(idx); let thread_node = &threads.thread_nodes()[thread_node]; @@ -216,6 +224,7 @@ impl CompactListing { } threads.thread_nodes()[iter_ptr].message().unwrap() }; + let root_envelope: &Envelope = &mailbox.collection[&i]; let fg_color = if !root_envelope.is_seen() { Color::Byte(0) @@ -253,7 +262,12 @@ impl CompactListing { let bottom_right = bottom_right!(area); if self.length == 0 { clear_area(grid, area); - copy_area(grid, &self.content, area, ((0, 0), (MAX_COLS - 1, 0))); + copy_area( + grid, + &self.content, + area, + ((0, 0), (MAX_COLS - 1, self.length)), + ); context.dirty_areas.push_back(area); return; } @@ -346,7 +360,6 @@ impl Component for CompactListing { if !self.is_dirty() { return; } - self.dirty = false; /* Draw the entire list */ self.draw_list(grid, area, context); } else { @@ -365,8 +378,8 @@ impl Component for CompactListing { } self.view = Some(ThreadView::new(self.cursor_pos, None, context)); self.view.as_mut().unwrap().draw(grid, area, context); - self.dirty = false; } + self.dirty = false; } fn process_event(&mut self, event: &UIEvent, context: &mut Context) -> bool { if let Some(ref mut v) = self.view { diff --git a/ui/src/components/mail/listing/mod.rs b/ui/src/components/mail/listing/mod.rs index d600d33a..4bd6898d 100644 --- a/ui/src/components/mail/listing/mod.rs +++ b/ui/src/components/mail/listing/mod.rs @@ -49,7 +49,7 @@ impl fmt::Display for Listing { impl Default for Listing { fn default() -> Self { - Listing::Compact(Default::default()) + Listing::Threaded(Default::default()) } } diff --git a/ui/src/components/mail/listing/thread.rs b/ui/src/components/mail/listing/thread.rs index efc3a291..9df89568 100644 --- a/ui/src/components/mail/listing/thread.rs +++ b/ui/src/components/mail/listing/thread.rs @@ -35,10 +35,13 @@ pub struct ThreadListing { subsort: (SortField, SortOrder), /// Cache current view. content: CellBuffer, + + locations: Vec<(usize, usize)>, /// If we must redraw on next redraw event dirty: bool, /// If `self.view` exists or not. unfocused: bool, + initialised: bool, view: Option<MailView>, } @@ -64,17 +67,24 @@ impl ThreadListing { sort: (Default::default(), Default::default()), subsort: (Default::default(), Default::default()), content, + locations: Vec::new(), dirty: true, unfocused: false, view: None, + initialised: false, } } /// Fill the `self.content` `CellBuffer` with the contents of the account folder the user has /// chosen. fn refresh_mailbox(&mut self, context: &mut Context) { self.dirty = true; - self.cursor_pos.2 = 0; - self.new_cursor_pos.2 = 0; + if !(self.cursor_pos.0 == self.new_cursor_pos.0 + && self.cursor_pos.1 == self.new_cursor_pos.1) + { + //TODO: store cursor_pos in each folder + 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; @@ -85,20 +95,27 @@ impl ThreadListing { }); // 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; + 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] .as_ref() .unwrap(); - self.length = mailbox.collection.threads.root_len(); + self.length = mailbox.collection.threads.len(); self.content = CellBuffer::new(MAX_COLS, self.length + 1, Cell::with_char(' ')); if self.length == 0 { write_string_to_grid( @@ -118,25 +135,19 @@ impl ThreadListing { let threads = &mailbox.collection.threads; threads.sort_by(self.sort, self.subsort, &mailbox.collection); let thread_nodes: &Vec<ThreadNode> = &threads.thread_nodes(); - let mut iter = threads.root_iter().peekable(); - let len = threads.root_len().to_string().chars().count(); + self.locations = threads.threads_iter().collect(); + let mut iter = self.locations.iter().peekable(); /* This is just a desugared for loop so that we can use .peek() */ let mut idx = 0; - while let Some(i) = iter.next() { - let thread_node = &thread_nodes[i]; - - if !thread_node.has_message() { - continue; - } - - let indentation = thread_node.indentation(); + while let Some((indentation, i)) = iter.next() { + let thread_node = &thread_nodes[*i]; - if indentation == 0 { + if *indentation == 0 { thread_idx += 1; } match iter.peek() { - Some(&x) if thread_nodes[x].indentation() == indentation => { + Some((x, _)) if *x == *indentation => { indentations.pop(); indentations.push(true); } @@ -145,51 +156,58 @@ impl ThreadListing { indentations.push(false); } } - if threads.has_sibling(i) { + if threads.has_sibling(*i) { indentations.pop(); indentations.push(true); } - let envelope: &Envelope = &mailbox.collection[&thread_node.message().unwrap()]; - let fg_color = if !envelope.is_seen() { - Color::Byte(0) - } else { - Color::Default - }; - let bg_color = if !envelope.is_seen() { - Color::Byte(251) - } else if thread_idx % 2 == 0 { - Color::Byte(236) + if thread_node.has_message() { + let envelope: &Envelope = &mailbox.collection[&thread_node.message().unwrap()]; + let fg_color = if !envelope.is_seen() { + Color::Byte(0) + } else { + Color::Default + }; + let bg_color = if !envelope.is_seen() { + Color::Byte(251) + } else if thread_idx % 2 == 0 { + Color::Byte(236) + } else { + Color::Default + }; + let (x, _) = write_string_to_grid( + &ThreadListing::make_thread_entry( + envelope, + idx, + *indentation, + *i, + threads, + &indentations, + self.length, + // context.accounts[self.cursor_pos.0].backend.operation(envelope.hash()) + ), + &mut self.content, + fg_color, + bg_color, + ((0, idx), (MAX_COLS - 1, idx)), + false, + ); + for x in x..MAX_COLS { + self.content[(x, idx)].set_ch(' '); + self.content[(x, idx)].set_bg(bg_color); + } } else { - Color::Default - }; - let (x, _) = write_string_to_grid( - &ThreadListing::make_thread_entry( - envelope, - idx, - indentation, - i, - threads, - &indentations, - len, - // context.accounts[self.cursor_pos.0].backend.operation(envelope.hash()) - ), - &mut self.content, - fg_color, - bg_color, - ((0, idx), (MAX_COLS - 1, idx)), - false, - ); - for x in x..MAX_COLS { - self.content[(x, idx)].set_ch(' '); - self.content[(x, idx)].set_bg(bg_color); + for x in 0..MAX_COLS { + self.content[(x, idx)].set_ch(' '); + self.content[(x, idx)].set_bg(Color::Default); + } } match iter.peek() { - Some(&x) if thread_nodes[x].indentation() > indentation => { + Some((x, _)) if *x > *indentation => { indentations.push(false); } - Some(&x) if thread_nodes[x].indentation() < indentation => { - for _ in 0..(indentation - thread_nodes[x].indentation()) { + Some((x, _)) if *x < *indentation => { + for _ in 0..(*indentation - *x) { indentations.pop(); } } @@ -203,49 +221,64 @@ impl ThreadListing { let mailbox = &context.accounts[self.cursor_pos.0][self.cursor_pos.1] .as_ref() .unwrap(); - let envelope: &Envelope = mailbox.thread_to_mail(idx); + if mailbox.len() == 0 { + return; + } + if let Some(hash) = + mailbox.collection.threads.thread_nodes()[self.locations[idx].1].message() + { + let envelope: &Envelope = &mailbox.collection[&hash]; - let fg_color = if !envelope.is_seen() { - Color::Byte(0) - } else { - Color::Default - }; - let bg_color = if !envelope.is_seen() { - Color::Byte(251) - } else if idx % 2 == 0 { - Color::Byte(236) - } else { - Color::Default - }; - change_colors( - &mut self.content, - ((0, idx), (MAX_COLS - 1, idx)), - fg_color, - bg_color, - ); + let fg_color = if !envelope.is_seen() { + Color::Byte(0) + } else { + Color::Default + }; + let bg_color = if !envelope.is_seen() { + Color::Byte(251) + } else if idx % 2 == 0 { + Color::Byte(236) + } else { + Color::Default + }; + change_colors( + &mut self.content, + ((0, idx), (MAX_COLS - 1, idx)), + fg_color, + bg_color, + ); + } } fn highlight_line(&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 envelope: &Envelope = mailbox.thread_to_mail(idx); + if mailbox.len() == 0 || mailbox.len() <= idx { + return; + } - let fg_color = if !envelope.is_seen() { - Color::Byte(0) - } else { - Color::Default - }; - let bg_color = if self.cursor_pos.2 == idx { - Color::Byte(246) - } else if !envelope.is_seen() { - Color::Byte(251) - } else if idx % 2 == 0 { - Color::Byte(236) - } else { - Color::Default - }; - change_colors(grid, area, fg_color, bg_color); + if let Some(hash) = + mailbox.collection.threads.thread_nodes()[self.locations[idx].1].message() + { + let envelope: &Envelope = &mailbox.collection[&hash]; + + let fg_color = if !envelope.is_seen() { + Color::Byte(0) + } else { + Color::Default + }; + let bg_color = if self.cursor_pos.2 == idx { + Color::Byte(246) + } else if !envelope.is_seen() { + Color::Byte(251) + } else if idx % 2 == 0 { + Color::Byte(236) + } else { + Color::Default + }; + change_colors(grid, area, fg_color, bg_color); + } } /// Draw the list of `Envelope`s. @@ -266,7 +299,25 @@ impl ThreadListing { let page_no = (self.new_cursor_pos.2).wrapping_div(rows); let top_idx = page_no * rows; - + if !self.initialised { + self.initialised = false; + copy_area( + grid, + &self.content, + area, + ((0, top_idx), (MAX_COLS - 1, self.length)), + ); + self.highlight_line( + grid, + ( + set_y(upper_left, get_y(upper_left) + (self.cursor_pos.2 % rows)), + set_y(bottom_right, get_y(upper_left) + (self.cursor_pos.2 % rows)), + ), + self.cursor_pos.2, + context, + ); + context.dirty_areas.push_back(area); + } /* If cursor position has changed, remove the highlight from the previous position and * apply it in the new one. */ if self.cursor_pos.2 != self.new_cursor_pos.2 && prev_page_no == page_no { @@ -402,8 +453,26 @@ impl Component for ThreadListing { context.dirty_areas.push_back(area); return; } - /* Mark message as read */ + let idx = self.cursor_pos.2; + + { + let has_message: bool = { + let account = &context.accounts[self.cursor_pos.0]; + let mailbox = &account[self.cursor_pos.1].as_ref().unwrap(); + mailbox.collection.threads.thread_nodes() + [self.locations[self.new_cursor_pos.2].1] + .message() + .is_some() + }; + if !has_message { + self.dirty = false; + /* Draw the entire list */ + return self.draw_list(grid, area, context); + } + } + + /* Mark message as read */ let must_highlight = { if self.length == 0 { false @@ -411,7 +480,8 @@ impl Component for ThreadListing { let account = &mut context.accounts[self.cursor_pos.0]; let (hash, is_seen) = { let mailbox = &mut account[self.cursor_pos.1].as_mut().unwrap(); - let envelope: &mut Envelope = mailbox.thread_to_mail_mut(idx); + let envelope: &mut Envelope = + mailbox.thread_to_mail_mut(self.locations[self.new_cursor_pos.2].1); (envelope.hash(), envelope.is_seen()) }; if !is_seen { @@ -424,7 +494,8 @@ impl Component for ThreadListing { backend.operation(hash, folder_hash) }; let mailbox = &mut account[self.cursor_pos.1].as_mut().unwrap(); - let envelope: &mut Envelope = mailbox.thread_to_mail_mut(idx); + let envelope: &mut Envelope = + mailbox.thread_to_mail_mut(self.locations[self.new_cursor_pos.2].1); envelope.set_seen(op).unwrap(); true } else { @@ -476,7 +547,7 @@ impl Component for ThreadListing { let coordinates = ( self.cursor_pos.0, self.cursor_pos.1, - mailbox.threaded_mail(self.cursor_pos.2), + mailbox.threaded_mail(self.locations[self.cursor_pos.2].1), ); self.view = Some(MailView::new(coordinates, None, None)); } @@ -587,6 +658,7 @@ impl Component for ThreadListing { if *idxa == self.new_cursor_pos.0 && *idxf == self.new_cursor_pos.1 { self.dirty = true; self.refresh_mailbox(context); + eprintln!("mailboxupdate"); } } UIEventType::ChangeMode(UIMode::Normal) => { @@ -596,8 +668,8 @@ impl Component for ThreadListing { self.dirty = true; } UIEventType::Action(ref action) => match action { - Action::ViewMailbox(idx) => { - self.new_cursor_pos.1 = *idx; + Action::ViewMailbox(idx_m) => { + self.new_cursor_pos.1 = *idx_m; self.dirty = true; self.refresh_mailbox(context); return true; diff --git a/ui/src/components/mail/mod.rs b/ui/src/components/mail/mod.rs index 62f9243c..f3dbc19a 100644 --- a/ui/src/components/mail/mod.rs +++ b/ui/src/components/mail/mod.rs @@ -70,8 +70,7 @@ impl AccountMenu { } entries }, - }) - .collect(); + }).collect(); AccountMenu { accounts, dirty: true, diff --git a/ui/src/components/mod.rs b/ui/src/components/mod.rs index 4eba1579..a3ffa21c 100644 --- a/ui/src/components/mod.rs +++ b/ui/src/components/mod.rs @@ -32,6 +32,9 @@ pub use mail::*; pub mod notifications; +pub mod indexer; +pub use self::indexer::*; + pub mod utilities; pub use self::utilities::*; diff --git a/ui/src/lib.rs b/ui/src/lib.rs index 2482eec3..7a8ba50a 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -59,3 +59,6 @@ pub use components::*; pub mod conf; pub use conf::*; + +pub mod workers; +pub use workers::*; diff --git a/ui/src/state.rs b/ui/src/state.rs index 23879f19..b9a6ef6f 100644 --- a/ui/src/state.rs +++ b/ui/src/state.rs @@ -100,14 +100,14 @@ impl Context { pub fn restore_input(&self) { self.input.restore(self.sender.clone()); } - pub fn account_status(&mut self, idx_a: usize, idx_m: usize) -> result::Result<bool, usize> { + pub fn account_status(&mut self, idx_a: usize, idx_m: usize) -> result::Result<(), usize> { match self.accounts[idx_a].status(idx_m) { Ok(()) => { self.replies.push_back(UIEvent { id: 0, event_type: UIEventType::MailboxUpdate((idx_a, idx_m)), }); - Ok(true) + Ok(()) } Err(n) => Err(n), } @@ -127,6 +127,7 @@ pub struct State { entities: Vec<Entity>, pub context: Context, threads: FnvHashMap<thread::ThreadId, (chan::Sender<bool>, thread::JoinHandle<()>)>, + work_controller: WorkController, } impl Drop for State { @@ -155,7 +156,7 @@ impl State { pub fn new() -> Self { /* Create a channel to communicate with other threads. The main process is the sole receiver. * */ - let (sender, receiver) = chan::sync(::std::mem::size_of::<ThreadEvent>()); + let (sender, receiv |