diff options
author | Manos Pitsidianakis <el13635@mail.ntua.gr> | 2018-08-23 14:39:54 +0300 |
---|---|---|
committer | Manos Pitsidianakis <el13635@mail.ntua.gr> | 2019-06-10 19:40:31 +0300 |
commit | b617fc013681f3c2a9b6f49fa6e2af8261bf99c7 (patch) | |
tree | 4144695055ea051cddfc0e6341537d053fc72186 /ui/src | |
parent | ad5d2353e835b0ec62453bc2462ada7b06a11bf0 (diff) |
ThreadView and compact listing
closes #3
Diffstat (limited to 'ui/src')
-rw-r--r-- | ui/src/components/mail/compose.rs | 16 | ||||
-rw-r--r-- | ui/src/components/mail/listing/compact.rs | 31 | ||||
-rw-r--r-- | ui/src/components/mail/listing/mod.rs | 47 | ||||
-rw-r--r-- | ui/src/components/mail/mod.rs | 3 | ||||
-rw-r--r-- | ui/src/components/mail/view/envelope.rs | 35 | ||||
-rw-r--r-- | ui/src/components/mail/view/html.rs | 10 | ||||
-rw-r--r-- | ui/src/components/mail/view/mod.rs | 74 | ||||
-rw-r--r-- | ui/src/components/mail/view/thread.rs | 300 | ||||
-rw-r--r-- | ui/src/components/mod.rs | 20 | ||||
-rw-r--r-- | ui/src/components/notifications.rs | 4 | ||||
-rw-r--r-- | ui/src/components/utilities.rs | 54 | ||||
-rw-r--r-- | ui/src/types/accounts.rs | 6 | ||||
-rw-r--r-- | ui/src/types/cells.rs | 3 |
13 files changed, 426 insertions, 177 deletions
diff --git a/ui/src/components/mail/compose.rs b/ui/src/components/mail/compose.rs index ce9033f5..edb30be7 100644 --- a/ui/src/components/mail/compose.rs +++ b/ui/src/components/mail/compose.rs @@ -21,6 +21,7 @@ use super::*; +#[derive(Debug)] pub struct Composer { dirty: bool, mode: ViewMode, @@ -39,6 +40,7 @@ impl Default for Composer { } } +#[derive(Debug)] enum ViewMode { //Compose, Overview, @@ -56,10 +58,6 @@ impl Component for Composer { if self.dirty { clear_area(grid, area); } - if !self.buffer.is_empty() { - eprintln!("{:?}", EnvelopeWrapper::new(self.buffer.as_bytes().to_vec())); - - } let upper_left = upper_left!(area); let bottom_right = bottom_right!(area); @@ -104,7 +102,11 @@ impl Component for Composer { } } - fn process_event(&mut self, event: &UIEvent, context: &mut Context) { + fn process_event(&mut self, event: &UIEvent, context: &mut Context) -> bool { + if self.pager.process_event(event, context) { + return true; + } + match event.event_type { UIEventType::Resize => { self.dirty = true; @@ -135,11 +137,11 @@ impl Component for Composer { self.pager.update_from_string(result); context.restore_input(); self.dirty = true; - return; + return true; }, _ => {}, } - self.pager.process_event(event, context); + false } fn is_dirty(&self) -> bool { diff --git a/ui/src/components/mail/listing/compact.rs b/ui/src/components/mail/listing/compact.rs index 0ccebd72..96ab3d94 100644 --- a/ui/src/components/mail/listing/compact.rs +++ b/ui/src/components/mail/listing/compact.rs @@ -27,6 +27,7 @@ const MAX_COLS: usize = 500; /// A list of all mail (`Envelope`s) in a `Mailbox`. On `\n` it opens the `Envelope` content in a /// `ThreadView`. +#[derive(Debug)] pub struct CompactListing { /// (x, y, z): x is accounts, y is folders, z is index inside a folder. cursor_pos: (usize, usize, usize), @@ -301,7 +302,7 @@ impl Component for CompactListing { } return; } - self.view = Some(ThreadView::new(self.cursor_pos)); + self.view = Some(ThreadView::new(self.cursor_pos, context)); self.view.as_mut().unwrap().draw( grid, area, @@ -310,28 +311,37 @@ impl Component for CompactListing { self.dirty = false; } } - fn process_event(&mut self, event: &UIEvent, context: &mut Context) { + fn process_event(&mut self, event: &UIEvent, context: &mut Context) -> bool { + if let Some(ref mut v) = self.view { + if v.process_event(event, context) { + return true; + } + } match event.event_type { UIEventType::Input(Key::Up) => { if self.cursor_pos.2 > 0 { - self.new_cursor_pos.2 -= 1; + self.new_cursor_pos.2 = self.new_cursor_pos.2.saturating_sub(1); self.dirty = true; } + return true; } UIEventType::Input(Key::Down) => { if self.length > 0 && self.new_cursor_pos.2 < self.length - 1 { self.new_cursor_pos.2 += 1; self.dirty = true; } + return true; } UIEventType::Input(Key::Char('\n')) if !self.unfocused => { self.unfocused = true; self.dirty = true; + return true; } UIEventType::Input(Key::Char('i')) if self.unfocused => { self.unfocused = false; self.dirty = true; self.view = None; + return true; } UIEventType::Input(Key::Char(k @ 'J')) | UIEventType::Input(Key::Char(k @ 'K')) => { let folder_length = context.accounts[self.cursor_pos.0].len(); @@ -364,6 +374,7 @@ impl Component for CompactListing { } _ => {} } + return true; } UIEventType::Input(Key::Char(k @ 'h')) | UIEventType::Input(Key::Char(k @ 'l')) => { let accounts_length = context.accounts.len(); @@ -382,6 +393,7 @@ impl Component for CompactListing { } _ => {} } + return true; } UIEventType::RefreshMailbox(_) => { self.dirty = true; @@ -391,7 +403,6 @@ impl Component for CompactListing { if *idxa == self.new_cursor_pos.0 && *idxf == self.new_cursor_pos.1 { self.dirty = true; self.refresh_mailbox(context); - return; } } UIEventType::ChangeMode(UIMode::Normal) => { @@ -408,35 +419,33 @@ impl Component for CompactListing { .toggle_threaded(); self.refresh_mailbox(context); self.dirty = true; - return; + return true; } Action::ViewMailbox(idx) => { self.new_cursor_pos.1 = *idx; self.dirty = true; self.refresh_mailbox(context); - return; + return true; } Action::SubSort(field, order) => { eprintln!("SubSort {:?} , {:?}", field, order); self.subsort = (*field, *order); self.dirty = true; self.refresh_mailbox(context); - return; + return true; } Action::Sort(field, order) => { eprintln!("Sort {:?} , {:?}", field, order); self.sort = (*field, *order); self.dirty = true; self.refresh_mailbox(context); - return; + return true; } // _ => {} }, _ => {} } - if let Some(ref mut v) = self.view { - v.process_event(event, context); - } + false } fn is_dirty(&self) -> bool { self.dirty || self.view.as_ref().map(|p| p.is_dirty()).unwrap_or(false) diff --git a/ui/src/components/mail/listing/mod.rs b/ui/src/components/mail/listing/mod.rs index f6672d18..132f4408 100644 --- a/ui/src/components/mail/listing/mod.rs +++ b/ui/src/components/mail/listing/mod.rs @@ -28,6 +28,7 @@ const MAX_COLS: usize = 500; /// A list of all mail (`Envelope`s) in a `Mailbox`. On `\n` it opens the `Envelope` content in a /// `MailView`. +#[derive(Debug)] pub struct MailListing { /// (x, y, z): x is accounts, y is folders, z is index inside a folder. cursor_pos: (usize, usize, usize), @@ -591,7 +592,23 @@ impl Component for MailListing { } return; } - self.view = Some(MailView::new(self.cursor_pos, self.local_collection.clone(), None, None)); + { + let threaded = context.accounts[self.cursor_pos.0] + .runtime_settings + .conf() + .threaded(); + let account = &context.accounts[self.cursor_pos.0]; + let mailbox = &account[self.cursor_pos.1] + .as_ref() + .unwrap(); + let mut coordinates = self.cursor_pos; + coordinates.2 = if threaded { + mailbox.threaded_mail(self.cursor_pos.2) + } else { + self.local_collection[self.cursor_pos.2] + }; + self.view = Some(MailView::new(coordinates, None, None)); + } self.view.as_mut().unwrap().draw( grid, (set_y(upper_left, mid + 1), bottom_right), @@ -600,23 +617,31 @@ impl Component for MailListing { self.dirty = false; } } - fn process_event(&mut self, event: &UIEvent, context: &mut Context) { + fn process_event(&mut self, event: &UIEvent, context: &mut Context) -> bool { + if let Some(ref mut v) = self.view { + if v.process_event(event, context) { + return true; + } + } match event.event_type { UIEventType::Input(Key::Up) => { if self.cursor_pos.2 > 0 { self.new_cursor_pos.2 -= 1; self.dirty = true; } + return true; } UIEventType::Input(Key::Down) => { if self.length > 0 && self.new_cursor_pos.2 < self.length - 1 { self.new_cursor_pos.2 += 1; self.dirty = true; } + return true; } UIEventType::Input(Key::Char('\n')) if !self.unfocused => { self.unfocused = true; self.dirty = true; + return true; } UIEventType::Input(Key::Char('m')) if !self.unfocused => { use std::process::{Command, Stdio}; @@ -662,12 +687,13 @@ impl Component for MailListing { id: 0, event_type: UIEventType::ChangeMode(UIMode::Fork), }); - return; + return true; } UIEventType::Input(Key::Char('i')) if self.unfocused => { self.unfocused = false; self.dirty = true; self.view = None; + return true; } UIEventType::Input(Key::Char(k @ 'J')) | UIEventType::Input(Key::Char(k @ 'K')) => { let folder_length = context.accounts[self.cursor_pos.0].len(); @@ -700,6 +726,7 @@ impl Component for MailListing { } _ => {} } + return true; } UIEventType::Input(Key::Char(k @ 'h')) | UIEventType::Input(Key::Char(k @ 'l')) => { let accounts_length = context.accounts.len(); @@ -718,6 +745,7 @@ impl Component for MailListing { } _ => {} } + return true; } UIEventType::RefreshMailbox(_) => { self.dirty = true; @@ -727,7 +755,6 @@ impl Component for MailListing { if *idxa == self.new_cursor_pos.0 && *idxf == self.new_cursor_pos.1 { self.dirty = true; self.refresh_mailbox(context); - return; } } UIEventType::ChangeMode(UIMode::Normal) => { @@ -744,35 +771,33 @@ impl Component for MailListing { .toggle_threaded(); self.refresh_mailbox(context); self.dirty = true; - return; + return true; } Action::ViewMailbox(idx) => { self.new_cursor_pos.1 = *idx; self.dirty = true; self.refresh_mailbox(context); - return; + return true; } Action::SubSort(field, order) => { eprintln!("SubSort {:?} , {:?}", field, order); self.subsort = (*field, *order); self.dirty = true; self.refresh_mailbox(context); - return; + return true; } Action::Sort(field, order) => { eprintln!("Sort {:?} , {:?}", field, order); self.sort = (*field, *order); self.dirty = true; self.refresh_mailbox(context); - return; + return true; } // _ => {} }, _ => {} } - if let Some(ref mut v) = self.view { - v.process_event(event, context); - } + false } fn is_dirty(&self) -> bool { self.dirty || self.view.as_ref().map(|p| p.is_dirty()).unwrap_or(false) diff --git a/ui/src/components/mail/mod.rs b/ui/src/components/mail/mod.rs index 5c4e8e85..24d1890d 100644 --- a/ui/src/components/mail/mod.rs +++ b/ui/src/components/mail/mod.rs @@ -234,7 +234,7 @@ impl Component for AccountMenu { context.dirty_areas.push_back(area); } - fn process_event(&mut self, event: &UIEvent, _context: &mut Context) { + fn process_event(&mut self, event: &UIEvent, _context: &mut Context) -> bool { match event.event_type { UIEventType::RefreshMailbox(c) => { self.cursor = Some(c); @@ -248,6 +248,7 @@ impl Component for AccountMenu { } _ => {} } + false } fn is_dirty(&self) -> bool { self.dirty diff --git a/ui/src/components/mail/view/envelope.rs b/ui/src/components/mail/view/envelope.rs index ac5d73da..8f043612 100644 --- a/ui/src/components/mail/view/envelope.rs +++ b/ui/src/components/mail/view/envelope.rs @@ -45,6 +45,7 @@ impl ViewMode { /// Contains an Envelope view, with sticky headers, a pager for the body, and subviews for more /// menus +#[derive(Debug)] pub struct EnvelopeView { pager: Option<Pager>, subview: Option<Box<Component>>, @@ -313,13 +314,24 @@ impl Component for EnvelopeView { } } - fn process_event(&mut self, event: &UIEvent, context: &mut Context) { + fn process_event(&mut self, event: &UIEvent, context: &mut Context) -> bool { + if let Some(ref mut sub) = self.subview { + if sub.process_event(event, context) { + return true; + } + } else if let Some(ref mut p) = self.pager { + if p.process_event(event, context) { + return true; + } + } match event.event_type { UIEventType::Input(Key::Esc) => { self.cmd_buf.clear(); + return true; } UIEventType::Input(Key::Char(c)) if c >= '0' && c <= '9' => { self.cmd_buf.push(c); + return true; } UIEventType::Input(Key::Char('r')) if self.mode == ViewMode::Normal || self.mode == ViewMode::Raw => @@ -330,11 +342,13 @@ impl Component for EnvelopeView { ViewMode::Raw }; self.dirty = true; + return true; } UIEventType::Input(Key::Char('r')) if self.mode.is_attachment() || self.mode == ViewMode::Subview => { self.mode = ViewMode::Normal; self.subview.take(); self.dirty = true; + return true; } UIEventType::Input(Key::Char('a')) if !self.cmd_buf.is_empty() && self.mode == ViewMode::Normal => @@ -362,7 +376,7 @@ impl Component for EnvelopeView { "Multipart attachments are not supported yet.".to_string(), ), }); - return; + return true; } ContentType::Unsupported { .. } => { let attachment_type = u.mime_type(); @@ -386,7 +400,7 @@ impl Component for EnvelopeView { attachment_type )), }); - return; + return true; } } } @@ -398,10 +412,11 @@ impl Component for EnvelopeView { lidx )), }); - return; + return true; } }; - } + return true; + }, UIEventType::Input(Key::Char('g')) if !self.cmd_buf.is_empty() && self.mode == ViewMode::Url => { @@ -422,7 +437,7 @@ impl Component for EnvelopeView { lidx )), }); - return; + return true; } }; @@ -432,6 +447,7 @@ impl Component for EnvelopeView { .stdout(Stdio::piped()) .spawn() .expect("Failed to start xdg_open"); + return true; } UIEventType::Input(Key::Char('u')) => { match self.mode { @@ -440,14 +456,11 @@ impl Component for EnvelopeView { _ => {} } self.dirty = true; + return true; } _ => {} } - if let Some(ref mut sub) = self.subview { - sub.process_event(event, context); - } else if let Some(ref mut p) = self.pager { - p.process_event(event, context); - } + false } fn is_dirty(&self) -> bool { self.dirty diff --git a/ui/src/components/mail/view/html.rs b/ui/src/components/mail/view/html.rs index 1fdc5875..bb308a0f 100644 --- a/ui/src/components/mail/view/html.rs +++ b/ui/src/components/mail/view/html.rs @@ -23,6 +23,7 @@ use super::*; use std::io::Write; use std::process::{Command, Stdio}; +#[derive(Debug)] pub struct HtmlView { pager: Pager, bytes: Vec<u8>, @@ -65,7 +66,10 @@ impl Component for HtmlView { fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) { self.pager.draw(grid, area, context); } - fn process_event(&mut self, event: &UIEvent, context: &mut Context) { + fn process_event(&mut self, event: &UIEvent, context: &mut Context) -> bool { + if self.pager.process_event(event, context) { + return true; + } match event.event_type { UIEventType::Input(Key::Char('v')) => { // TODO: Optional filter that removes outgoing resource requests (images and @@ -88,11 +92,11 @@ impl Component for HtmlView { )), }); } - return; + return true; } _ => {} } - self.pager.process_event(event, context); + false } fn is_dirty(&self) -> bool { self.pager.is_dirty() diff --git a/ui/src/components/mail/view/mod.rs b/ui/src/components/mail/view/mod.rs index ccbfe7ce..e830bd02 100644 --- a/ui/src/components/mail/view/mod.rs +++ b/ui/src/components/mail/view/mod.rs @@ -42,6 +42,12 @@ enum ViewMode { Subview, } +impl Default for ViewMode { + fn default() -> Self { + ViewMode::Normal + } +} + impl ViewMode { fn is_attachment(&self) -> bool { match self { @@ -53,9 +59,9 @@ impl ViewMode { /// Contains an Envelope view, with sticky headers, a pager for the body, and subviews for more /// menus +#[derive(Debug, Default)] pub struct MailView { coordinates: (usize, usize, usize), - local_collection: Vec<usize>, pager: Option<Pager>, subview: Option<Box<Component>>, dirty: bool, @@ -74,13 +80,11 @@ impl fmt::Display for MailView { impl MailView { pub fn new( coordinates: (usize, usize, usize), - local_collection: Vec<usize>, pager: Option<Pager>, subview: Option<Box<Component>>, ) -> Self { MailView { coordinates, - local_collection, pager, subview, dirty: true, @@ -207,24 +211,17 @@ impl Component for MailView { let upper_left = upper_left!(area); let bottom_right = bottom_right!(area); - let (envelope_idx, y): (usize, usize) = { + let y: usize = { let accounts = &mut context.accounts; - let threaded = accounts[self.coordinates.0].runtime_settings.conf().threaded(); let mailbox = &mut accounts[self.coordinates.0][self.coordinates.1] .as_ref() .unwrap(); - let envelope_idx: usize = if threaded { - mailbox.threaded_mail(self.coordinates.2) - } else { - self.local_collection[self.coordinates.2] - }; - - let envelope: &Envelope = &mailbox.collection[envelope_idx]; + let envelope: &Envelope = &mailbox.collection[self.coordinates.2]; if self.mode == ViewMode::Raw { clear_area(grid, area); context.dirty_areas.push_back(area); - (envelope_idx, get_y(upper_left) - 1) + get_y(upper_left) - 1 } else { let (x, y) = write_string_to_grid( &format!("Date: {}", envelope.date_as_str()), @@ -295,7 +292,7 @@ impl Component for MailView { context .dirty_areas .push_back((upper_left, set_y(bottom_right, y + 1))); - (envelope_idx, y + 1) + y + 1 } }; @@ -304,7 +301,7 @@ impl Component for MailView { let mailbox = &context.accounts[mailbox_idx.0][mailbox_idx.1] .as_ref() .unwrap(); - let envelope: &Envelope = &mailbox.collection[envelope_idx]; + let envelope: &Envelope = &mailbox.collection[mailbox_idx.2]; let op = context.accounts[mailbox_idx.0].backend.operation(envelope.hash()); let body = envelope.body(op); match self.mode { @@ -341,7 +338,16 @@ impl Component for MailView { } } - fn process_event(&mut self, event: &UIEvent, context: &mut Context) { + fn process_event(&mut self, event: &UIEvent, context: &mut Context) -> bool { + if let Some(ref mut sub) = self.subview { + if sub.process_event(event, context) { + return true; + } + } else if let Some(ref mut p) = self.pager { + if p.process_event(event, context) { + return true; + } + } match event.event_type { UIEventType::Input(Key::Esc) => { self.cmd_buf.clear(); @@ -372,17 +378,11 @@ impl Component for MailView { { let accounts = &context.accounts; - let threaded = accounts[self.coordinates.0].runtime_settings.conf().threaded(); let mailbox = &accounts[self.coordinates.0][self.coordinates.1] .as_ref() .unwrap(); - let envelope_idx: usize = if threaded { - mailbox.threaded_mail(self.coordinates.2) - } else { - self.local_collection[self.coordinates.2] - }; - let envelope: &Envelope = &mailbox.collection[envelope_idx]; + let envelope: &Envelope = &mailbox.collection[self.coordinates.2]; let op = context.accounts[self.coordinates.0].backend.operation(envelope.hash()); if let Some(u) = envelope.body(op).attachments().get(lidx) { match u.content_type() { @@ -391,7 +391,7 @@ impl Component for MailView { match EnvelopeWrapper::new(u.bytes().to_vec()) { Ok(wrapper) => { self.subview = Some(Box::new(EnvelopeView::new(wrapper, None, None))); - }, + }, Err(e) => { context.replies.push_back(UIEvent { id: 0, @@ -401,7 +401,7 @@ impl Component for MailView { }); } } - return; + return true; }, ContentType::Text { .. } => { @@ -415,7 +415,7 @@ impl Component for MailView { "Multipart attachments are not supported yet.".to_string(), ), }); - return; + return true; } ContentType::Unsupported { .. } => { let attachment_type = u.mime_type(); @@ -439,7 +439,7 @@ impl Component for MailView { attachment_type )), }); - return; + return true; } } } @@ -451,7 +451,7 @@ impl Component for MailView { lidx )), }); - return; + return true; } }; } @@ -462,17 +462,11 @@ impl Component for MailView { self.cmd_buf.clear(); let url = { let accounts = &context.accounts; - let threaded = accounts[self.coordinates.0].runtime_settings.conf().threaded(); let mailbox = &accounts[self.coordinates.0][self.coordinates.1] .as_ref() .unwrap(); - let envelope_idx: usize = if threaded { - mailbox.threaded_mail(self.coordinates.2) - } else { - self.local_collection[self.coordinates.2] - }; - let envelope: &Envelope = &mailbox.collection[envelope_idx]; + let envelope: &Envelope = &mailbox.collection[self.coordinates.2]; let finder = LinkFinder::new(); let op = context.accounts[self.coordinates.0].backend.operation(envelope.hash()); let mut t = envelope.body(op).text().to_string(); @@ -487,7 +481,7 @@ impl Component for MailView { lidx )), }); - return; + return true; } }; @@ -506,13 +500,9 @@ impl Component for MailView { } self.dirty = true; } - _ => {} - } - if let Some(ref mut sub) = self.subview { - sub.process_event(event, context); - } else if let Some(ref mut p) = self.pager { - p.process_event(event, context); + _ => { return false; } } + true } fn is_dirty(&self) -> bool { self.dirty diff --git a/ui/src/components/mail/view/thread.rs b/ui/src/components/mail/view/thread.rs index eedc1038..e00c0724 100644 --- a/ui/src/components/mail/view/thread.rs +++ b/ui/src/components/mail/view/thread.rs @@ -20,6 +20,7 @@ */ use super::*; +use std::cmp; #[derive(Debug)] struct ThreadEntry { @@ -28,30 +29,113 @@ struct ThreadEntry { content: CellBuffer, msg_idx: usize, - expanded: bool, } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct ThreadView { + new_cursor_pos: usize, + cursor_pos: usize, + expanded_pos: usize, + new_expanded_pos: usize, dirty: bool, coordinates: (usize, usize, usize), - pager: Pager, + mailview: MailView, entries: Vec<ThreadEntry>, + content: CellBuffer, + initiated: bool, } impl ThreadView { - pub fn new(coordinates: (usize, usize, usize), - ) -> Self { - ThreadView { + pub fn new(coordinates: (usize, usize, usize), context: &Context) -> Self { + let mut stack: Vec<(usize, usize)> = Vec::with_capacity(32); + let mailbox = &context.accounts[coordinates.0][coordinates.1].as_ref().unwrap(); + let threads = &mailbox.threads; + let container = &threads.containers()[threads.root_set()[coordinates.2]]; + + if container.message().is_some() { + stack.push((0, threads.root_set()[coordinates.2])); + } else { + stack.push((1, container.first_child().unwrap())); + } + let mut view = ThreadView { dirty: true, + initiated: false, coordinates, - pager: Pager::default(), + mailview: MailView::default(), entries: Vec::new(), + cursor_pos: 1, + new_cursor_pos: 0, + .. Default::default() + }; + let mut line = 0; + let mut max_ind = 0; + while let Some((ind, idx)) = stack.pop() { + max_ind = cmp::max(max_ind, ind); + let entry = view.make_entry(context, (ind, idx, line)); + view.entries.push(entry); + line += 1; + let container = &threads.containers()[idx]; + if let Some(i) = container.next_sibling() { + stack.push((ind, i)); + } + + if let Some(i) = container.first_child() { + stack.push((ind + 1, i)); + } + } + view.new_expanded_pos = view.entries.len() - 1; + view.expanded_pos = view.new_expanded_pos + 1; + + let height = 2*view.entries.len(); + let mut width = 0; + + let mut strings: Vec<String> = Vec::with_capacity(view.entries.len()); + + + for e in &view.entries { + let envelope: &Envelope = &mailbox.collection[e.msg_idx]; + strings.push(format!(" {}{} - {}", " ".repeat(e.index.0 * 4), envelope.date_as_str(), envelope.from_to_string())); + width = cmp::max(width, e.index.0 + strings.last().as_ref().unwrap().len() + 1); + } + let mut content = CellBuffer::new(width, height, Cell::default()); + for (y, e) in view.entries.iter().enumerate() { + if y > 0 && content.get_mut(e.index.0 * 4, 2*y - 1).is_some() { + let index = (e.index.0 * 4, 2*y - 1); + if content[index].ch() == ' ' { + let mut ctr = 1; + while content[(e.index.0 * 4 + ctr, 2 * y - 1)].ch() == ' ' { + content[(e.index.0 * 4 + ctr, 2 * y - 1)].set_ch(HORZ_BOUNDARY); + ctr += 1; + } + content[index].set_ch(_TOP_LEFT_CORNER); + } else { + content[index].set_ch(LIGHT_DOWN_AND_HORIZONTAL); + }; + } + + write_string_to_grid( + &strings[y], + &mut content, + Color::Default, + Color::Default, + ((e.index.0 + 1, 2*y), (width - 1, height - 1)), + true, + ); + content[(e.index.0 * 4, 2*y)].set_ch(VERT_BOUNDARY); + for i in (e.index.0 * 4)..width { + content[(i, 2*y + 1)].set_ch(HORZ_BOUNDARY); + } + content[(e.index.0 *4, 2*y + 1)].set_ch(LIGHT_UP_AND_HORIZONTAL); + } + //view.mailview = MailView::new((view.coordinates.0, view.coordinates.1, view.entries[view.expanded_pos].msg_idx), None, None); + view.content = content; + view.new_cursor_pos = view.new_expanded_pos; + view } - fn make_entry(&mut self, context: &mut Context, i: (usize, usize, usize)) -> ThreadEntry { + fn make_entry(&mut self, context: &Context, i: (usize, usize, usize)) -> ThreadEntry { let (ind, idx, order) = i; let mailbox = &context.accounts[self.coordinates.0][self.coordinates.1] .as_ref() @@ -90,7 +174,7 @@ impl ThreadView { & |