diff --git a/ui/src/components/mail/listing.rs b/ui/src/components/mail/listing.rs index 91813f4a..a419c81e 100644 --- a/ui/src/components/mail/listing.rs +++ b/ui/src/components/mail/listing.rs @@ -18,9 +18,9 @@ pub struct MailListing { content: CellBuffer, /// If we must redraw on next redraw event dirty: bool, - /// If `self.pager` exists or not. + /// If `self.view` exists or not. unfocused: bool, - pager: Option, + view: Option, } impl MailListing { @@ -39,7 +39,7 @@ impl MailListing { content: content, dirty: true, unfocused: false, - pager: None, + view: None, } } /// Fill the `self.content` `CellBuffer` with the contents of the account folder the user has @@ -126,7 +126,7 @@ impl MailListing { } else { Color::Default }; - let (x, y) = write_string_to_grid(&MailListing::make_thread_entry(envelope, idx, indentation, container, &indentations, len), + let (x, _) = write_string_to_grid(&MailListing::make_thread_entry(envelope, idx, indentation, container, &indentations, len), &mut content, fg_color, bg_color, @@ -272,23 +272,6 @@ impl MailListing { context.dirty_areas.push_back(area); } - /// Create a pager for the `Envelope` currently under the cursor. - fn draw_mail_view(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) { - { - let envelope_idx: usize = { - let threaded = context.accounts[self.cursor_pos.0].runtime_settings.threaded; - let mailbox = &mut context.accounts[self.cursor_pos.0][self.cursor_pos.1].as_ref().unwrap().as_ref().unwrap(); - if threaded { - mailbox.threaded_mail(self.cursor_pos.2) - } else { - self.cursor_pos.2 - } - }; - - self.pager = Some(Pager::from_envelope((self.cursor_pos.0, self.cursor_pos.1), envelope_idx, context)); - } - self.pager.as_mut().map(|p| p.draw(grid, area, context)); - } fn make_thread_entry(envelope: &Envelope, idx: usize, indent: usize, container: &Container, indentations: &Vec, idx_width: usize) -> String { let has_sibling = container.has_sibling(); @@ -341,7 +324,6 @@ impl MailListing { format!("{} days ago{}", n / (24*60*60), " ".repeat(9)) }, _ => { - let date = envelope.datetime(); envelope.datetime().format("%Y-%m-%d %H:%M:%S").to_string() }, @@ -358,9 +340,7 @@ impl Component for MailListing { } self.dirty = false; /* Draw the entire list */ - self.draw_list(grid, - area, - context); + self.draw_list(grid, area, context); } else { let upper_left = upper_left!(area); let bottom_right = bottom_right!(area); @@ -371,7 +351,7 @@ impl Component for MailListing { /* Render the mail body in a pager, basically copy what HSplit does */ let total_rows = get_y(bottom_right) - get_y(upper_left); - let pager_ratio = context.settings.pager.pager_ratio; + let pager_ratio = context.runtime_settings.pager.pager_ratio; let bottom_entity_rows = (pager_ratio*total_rows )/100; if bottom_entity_rows > total_rows { @@ -398,99 +378,17 @@ impl Component for MailListing { for i in get_x(upper_left)..=get_x(bottom_right) { grid[(i, mid)].set_ch('─'); } + context.dirty_areas.push_back((set_y(upper_left, mid), set_y(bottom_right, mid))); } // TODO: Make headers view configurable - /* Draw header */ - let y = - { - let threaded = context.accounts[self.cursor_pos.0].runtime_settings.threaded; - let mailbox = &mut context.accounts[self.cursor_pos.0][self.cursor_pos.1].as_ref().unwrap().as_ref().unwrap(); - let envelope: &Envelope = if threaded { - let i = mailbox.threaded_mail(self.cursor_pos.2); - &mailbox.collection[i] - } else { - &mailbox.collection[self.cursor_pos.2] - }; - - let (x,y) = write_string_to_grid(&format!("Date: {}", envelope.date_as_str()), - grid, - Color::Byte(33), - Color::Default, - (set_y(upper_left, mid+1), bottom_right), - true); - for x in x..=get_x(bottom_right) { - grid[(x, y)].set_ch(' '); - grid[(x, y)].set_bg(Color::Default); - grid[(x, y)].set_fg(Color::Default); - } - let (x,y) = write_string_to_grid(&format!("From: {}", envelope.from()), - grid, - Color::Byte(33), - Color::Default, - (set_y(upper_left, y+1), bottom_right), - true); - for x in x..=get_x(bottom_right) { - grid[(x, y)].set_ch(' '); - grid[(x, y)].set_bg(Color::Default); - grid[(x, y)].set_fg(Color::Default); - } - let (x,y) = write_string_to_grid(&format!("To: {}", envelope.to()), - grid, - Color::Byte(33), - Color::Default, - (set_y(upper_left, y+1), bottom_right), - true); - for x in x..=get_x(bottom_right) { - grid[(x, y)].set_ch(' '); - grid[(x, y)].set_bg(Color::Default); - grid[(x, y)].set_fg(Color::Default); - } - let (x,y) = write_string_to_grid(&format!("Subject: {}", envelope.subject()), - grid, - Color::Byte(33), - Color::Default, - (set_y(upper_left, y+1), bottom_right), - true); - for x in x..=get_x(bottom_right) { - grid[(x, y)].set_ch(' '); - grid[(x, y)].set_bg(Color::Default); - grid[(x, y)].set_fg(Color::Default); - } - let (x, y) = write_string_to_grid(&format!("Message-ID: {}", envelope.message_id_raw()), - grid, - Color::Byte(33), - Color::Default, - (set_y(upper_left, y+1), bottom_right), - true); - for x in x..=get_x(bottom_right) { - grid[(x, y)].set_ch(' '); - grid[(x, y)].set_bg(Color::Default); - grid[(x, y)].set_fg(Color::Default); - } - clear_area(grid, - (set_y(upper_left, y+1), set_y(bottom_right, y+2))); - context.dirty_areas.push_back((set_y(upper_left, mid), set_y(bottom_right, y+1))); - y + 2 - }; - - if !self.dirty { - if let Some(ref mut p) = self.pager { - p.draw(grid, - ((get_x(upper_left), y), bottom_right), - context); - } + self.view.as_mut().map(|v| v.draw(grid, (set_y(upper_left, mid + 1), bottom_right), context)); return; } - + self.view = Some(MailView::new(self.cursor_pos, None, None)); + self.view.as_mut().map(|v| v.draw(grid, (set_y(upper_left, mid + 1), bottom_right), context)); self.dirty = false; - - /* Draw body */ - self.draw_mail_view(grid, - ((get_x(upper_left), y), bottom_right), - context); - } } fn process_event(&mut self, event: &UIEvent, context: &mut Context) { @@ -561,7 +459,7 @@ impl Component for MailListing { UIEventType::Input(Key::Esc) | UIEventType::Input(Key::Char('i')) if self.unfocused == true => { self.unfocused = false; self.dirty = true; - self.pager = None; + self.view = None; }, UIEventType::Input(Key::Char(k @ 'J')) | UIEventType::Input(Key::Char(k @ 'K')) => { @@ -617,7 +515,7 @@ impl Component for MailListing { }, UIEventType::RefreshMailbox(_) => { self.dirty = true; - self.pager = None; + self.view = None; }, UIEventType::ChangeMode(UIMode::Normal) => { self.dirty = true; @@ -640,11 +538,11 @@ impl Component for MailListing { _ => { }, } - if let Some(ref mut p) = self.pager { - p.process_event(event, context); + if let Some(ref mut v) = self.view { + v.process_event(event, context); } } fn is_dirty(&self) -> bool { - self.dirty || self.pager.as_ref().map(|p| p.is_dirty()).unwrap_or(false) + 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 42dfa513..65e28ee3 100644 --- a/ui/src/components/mail/mod.rs +++ b/ui/src/components/mail/mod.rs @@ -3,7 +3,9 @@ use super::*; pub mod listing; +pub mod view; pub use listing::*; +pub use view::*; #[derive(Debug)] diff --git a/ui/src/components/mail/view.rs b/ui/src/components/mail/view.rs new file mode 100644 index 00000000..38d86501 --- /dev/null +++ b/ui/src/components/mail/view.rs @@ -0,0 +1,121 @@ +use super::*; + + +pub struct MailView { + coordinates: (usize, usize, usize), + pager: Option, + subview: Option>, + dirty: bool, +} + +impl MailView { + pub fn new(coordinates: (usize, usize, usize), pager: Option, subview: Option>) -> Self { + + MailView { + coordinates: coordinates, + pager: pager, + subview: subview, + dirty: true, + } + } +} + + +impl Component for MailView { + fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) { + let upper_left = upper_left!(area); + let bottom_right = bottom_right!(area); + + let (envelope_idx, y): (usize, usize) = { + let threaded = context.accounts[self.coordinates.0].runtime_settings.threaded; + let mailbox = &mut context.accounts[self.coordinates.0][self.coordinates.1].as_ref().unwrap().as_ref().unwrap(); + let envelope_idx: usize = if threaded { + mailbox.threaded_mail(self.coordinates.2) + } else { + self.coordinates.2 + }; + + let envelope: &Envelope = &mailbox.collection[envelope_idx]; + + let (x,y) = write_string_to_grid(&format!("Date: {}", envelope.date_as_str()), + grid, + Color::Byte(33), + Color::Default, + area, + true); + for x in x..=get_x(bottom_right) { + grid[(x, y)].set_ch(' '); + grid[(x, y)].set_bg(Color::Default); + grid[(x, y)].set_fg(Color::Default); + } + let (x,y) = write_string_to_grid(&format!("From: {}", envelope.from()), + grid, + Color::Byte(33), + Color::Default, + (set_y(upper_left, y+1), bottom_right), + true); + for x in x..=get_x(bottom_right) { + grid[(x, y)].set_ch(' '); + grid[(x, y)].set_bg(Color::Default); + grid[(x, y)].set_fg(Color::Default); + } + let (x,y) = write_string_to_grid(&format!("To: {}", envelope.to()), + grid, + Color::Byte(33), + Color::Default, + (set_y(upper_left, y+1), bottom_right), + true); + for x in x..=get_x(bottom_right) { + grid[(x, y)].set_ch(' '); + grid[(x, y)].set_bg(Color::Default); + grid[(x, y)].set_fg(Color::Default); + } + let (x,y) = write_string_to_grid(&format!("Subject: {}", envelope.subject()), + grid, + Color::Byte(33), + Color::Default, + (set_y(upper_left, y+1), bottom_right), + true); + for x in x..=get_x(bottom_right) { + grid[(x, y)].set_ch(' '); + grid[(x, y)].set_bg(Color::Default); + grid[(x, y)].set_fg(Color::Default); + } + let (x, y) = write_string_to_grid(&format!("Message-ID: {}", envelope.message_id_raw()), + grid, + Color::Byte(33), + Color::Default, + (set_y(upper_left, y+1), bottom_right), + true); + for x in x..=get_x(bottom_right) { + grid[(x, y)].set_ch(' '); + grid[(x, y)].set_bg(Color::Default); + grid[(x, y)].set_fg(Color::Default); + } + clear_area(grid, + (set_y(upper_left, y+1), set_y(bottom_right, y+2))); + context.dirty_areas.push_back((upper_left, set_y(bottom_right, y+1))); + (envelope_idx, y + 1) + }; + if self.dirty { + self.pager = Some(Pager::from_envelope((self.coordinates.0, self.coordinates.1), envelope_idx, context)); + self.dirty = false; + } + self.pager.as_mut().map(|p| p.draw(grid, (set_y(upper_left, y + 1),bottom_right), context)); + } + + fn process_event(&mut self, event: &UIEvent, context: &mut Context) { + 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); + } + } + } + fn is_dirty(&self) -> bool { + self.dirty || self.pager.as_ref().map(|p| p.is_dirty()).unwrap_or(false) || + self.subview.as_ref().map(|p| p.is_dirty()).unwrap_or(false) + } +} diff --git a/ui/src/components/utilities.rs b/ui/src/components/utilities.rs index 12bea00d..89df1d26 100644 --- a/ui/src/components/utilities.rs +++ b/ui/src/components/utilities.rs @@ -172,7 +172,7 @@ impl Pager { let mut text = text.to_string(); if envelope.body().count_attachments() > 1 { eprintln!("text was {}", text); - text = envelope.body().attachments().iter().fold(text, |mut s, a| { s.push_str(&format!("{}\n", a)); s }); + text = envelope.body().attachments().iter().enumerate().fold(text, |mut s, (idx, a)| { s.push_str(&format!("[{}] {}\n\n", idx, a)); s }); eprintln!("text is {}", text); } let mut lines: Vec<&str> = text.trim().split('\n').collect(); @@ -208,7 +208,6 @@ impl Pager { let width = lines.iter().map(|l| l.len()).max().unwrap_or(0); if width > 0 { for (i, l) in lines.iter().enumerate() { - eprintln!("line: {:?}", l); write_string_to_grid(l, content, Color::Default, @@ -235,11 +234,10 @@ impl Component for Pager { if self.height == 0 || self.height == self.cursor_pos || self.width == 0 { return; } + eprintln!("drawing"); clear_area(grid, (upper_left, bottom_right)); - context.dirty_areas.push_back((upper_left, bottom_right)); - //let pager_context: usize = context.settings.pager.pager_context; //let pager_stop: bool = context.settings.pager.pager_stop; //let rows = y(bottom_right) - y(upper_left); @@ -248,6 +246,7 @@ impl Component for Pager { context.dirty_areas.push_back(area); } fn process_event(&mut self, event: &UIEvent, _context: &mut Context) { + eprintln!("pager got {:?}", event); match event.event_type { UIEventType::Input(Key::Char('k')) => { if self.cursor_pos > 0 {