diff options
Diffstat (limited to 'ui')
-rw-r--r-- | ui/src/components/mail/view.rs | 251 |
1 files changed, 162 insertions, 89 deletions
diff --git a/ui/src/components/mail/view.rs b/ui/src/components/mail/view.rs index d7e7794e..649737ac 100644 --- a/ui/src/components/mail/view.rs +++ b/ui/src/components/mail/view.rs @@ -1,10 +1,9 @@ use super::*; -use linkify::{LinkFinder, Link}; +use linkify::{Link, LinkFinder}; use std::process::{Command, Stdio}; use mime_apps::query_default_app; - #[derive(PartialEq, Debug)] enum ViewMode { Normal, @@ -35,8 +34,11 @@ pub struct MailView { } impl MailView { - pub fn new(coordinates: (usize, usize, usize), pager: Option<Pager>, subview: Option<Box<MailView>>) -> Self { - + pub fn new( + coordinates: (usize, usize, usize), + pager: Option<Pager>, + subview: Option<Box<MailView>>, + ) -> Self { MailView { coordinates: coordinates, pager: pager, @@ -49,15 +51,20 @@ impl MailView { } } - 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 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 { @@ -66,98 +73,125 @@ impl Component for MailView { 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); + 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); + let (x, y) = write_string_to_grid( + &format!("From: {}", envelope.from_to_string()), + 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); + let (x, y) = write_string_to_grid( + &format!("To: {}", envelope.to_to_string()), + 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); + 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); + 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))); + 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 { let buf = { - let mailbox_idx = self.coordinates; // coordinates are mailbox idxs - let mailbox = &mut context.accounts[mailbox_idx.0][mailbox_idx.1].as_ref().unwrap().as_ref().unwrap(); - let envelope : &Envelope = &mailbox.collection[envelope_idx]; + let mailbox_idx = self.coordinates; // coordinates are mailbox idxs + let mailbox = &mut context.accounts[mailbox_idx.0][mailbox_idx.1] + .as_ref() + .unwrap() + .as_ref() + .unwrap(); + let envelope: &Envelope = &mailbox.collection[envelope_idx]; let finder = LinkFinder::new(); let mut text = match self.mode { ViewMode::Url => { let mut t = envelope.body().text().to_string(); for (lidx, l) in finder.links(&envelope.body().text()).enumerate() { - t.insert_str(l.start()+(lidx*3), &format!("[{}]", lidx)); + t.insert_str(l.start() + (lidx * 3), &format!("[{}]", lidx)); } if envelope.body().count_attachments() > 1 { - t = envelope.body().attachments().iter().enumerate().fold(t, |mut s, (idx, a)| { s.push_str(&format!("[{}] {}\n\n", idx, a)); s }); + t = envelope.body().attachments().iter().enumerate().fold( + t, + |mut s, (idx, a)| { + s.push_str(&format!("[{}] {}\n\n", idx, a)); + s + }, + ); } t - }, + } ViewMode::Attachment(aidx) => { let attachments = envelope.body().attachments(); let mut ret = format!("Viewing attachment. Press `r` to return \n"); ret.push_str(&attachments[aidx].text()); ret - }, + } _ => { let mut t = envelope.body().text().to_string(); if envelope.body().count_attachments() > 1 { - t = envelope.body().attachments().iter().enumerate().fold(t, |mut s, (idx, a)| { s.push_str(&format!("[{}] {}\n\n", idx, a)); s }); + t = envelope.body().attachments().iter().enumerate().fold( + t, + |mut s, (idx, a)| { + s.push_str(&format!("[{}] {}\n\n", idx, a)); + s + }, + ); } t - }, + } }; let mut buf = CellBuffer::from(&text); match self.mode { @@ -172,10 +206,10 @@ impl Component for MailView { buf[(l.start() + shift - 3, 0)].set_fg(Color::Byte(226)); } // Each Cell represents one char so next line will be: - shift += r.chars().count()+1; + shift += r.chars().count() + 1; } - }, - _ => {}, + } + _ => {} } buf }; @@ -188,29 +222,41 @@ impl Component for MailView { self.pager = Some(Pager::from_buf(buf, cursor_pos)); self.dirty = false; } - self.pager.as_mut().map(|p| p.draw(grid, (set_y(upper_left, y + 1),bottom_right), context)); + 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) { match event.event_type { UIEventType::Input(Key::Esc) => { self.cmd_buf.clear(); - }, - UIEventType::Input(Key::Char(c)) if c >= '0' && c <= '9' => { //TODO:this should be an Action + } + UIEventType::Input(Key::Char(c)) if c >= '0' && c <= '9' => { + //TODO:this should be an Action self.cmd_buf.push(c); - }, - UIEventType::Input(Key::Char('r')) if self.mode.is_attachment() => { //TODO:one quit shortcut? + } + UIEventType::Input(Key::Char('r')) if self.mode.is_attachment() => { + //TODO:one quit shortcut? self.mode = ViewMode::Normal; self.dirty = true; - }, - UIEventType::Input(Key::Char('a')) if self.cmd_buf.len() > 0 && self.mode == ViewMode::Normal => { //TODO:this should be an Action + } + UIEventType::Input(Key::Char('a')) + if self.cmd_buf.len() > 0 && self.mode == ViewMode::Normal => + { + //TODO:this should be an Action let lidx = self.cmd_buf.parse::<usize>().unwrap(); self.cmd_buf.clear(); { - 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 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 { @@ -223,11 +269,16 @@ impl Component for MailView { ContentType::Text => { self.mode = ViewMode::Attachment(lidx); self.dirty = true; - }, + } ContentType::Multipart { .. } => { - context.replies.push_back(UIEvent { id: 0, event_type: UIEventType::StatusNotification(format!("Multipart attachments are not supported yet.")) }); + context.replies.push_back(UIEvent { + id: 0, + event_type: UIEventType::StatusNotification(format!( + "Multipart attachments are not supported yet." + )), + }); return; - }, + } ContentType::Unsupported { .. } => { let attachment_type = u.mime_type(); let binary = query_default_app(&attachment_type); @@ -240,28 +291,45 @@ impl Component for MailView { .spawn() .expect(&format!("Failed to start {}", binary.display())); } else { - context.replies.push_back(UIEvent { id: 0, event_type: UIEventType::StatusNotification(format!("Couldn't find a default application for type {}", attachment_type)) }); + context.replies.push_back(UIEvent { + id: 0, + event_type: UIEventType::StatusNotification(format!( + "Couldn't find a default application for type {}", + attachment_type + )), + }); return; } - - }, + } } - } else { - context.replies.push_back(UIEvent { id: 0, event_type: UIEventType::StatusNotification(format!("Attachment `{}` not found.", lidx)) }); + context.replies.push_back(UIEvent { + id: 0, + event_type: UIEventType::StatusNotification(format!( + "Attachment `{}` not found.", + lidx + )), + }); return; } }; - - - }, - UIEventType::Input(Key::Char('g')) if self.cmd_buf.len() > 0 && self.mode == ViewMode::Url => { //TODO:this should be an Action + } + UIEventType::Input(Key::Char('g')) + if self.cmd_buf.len() > 0 && self.mode == ViewMode::Url => + { + //TODO:this should be an Action let lidx = self.cmd_buf.parse::<usize>().unwrap(); self.cmd_buf.clear(); let url = { - 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 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 { @@ -275,33 +343,37 @@ impl Component for MailView { if let Some(u) = links.get(lidx) { u.as_str().to_string() } else { - context.replies.push_back(UIEvent { id: 0, event_type: UIEventType::StatusNotification(format!("Link `{}` not found.", lidx)) }); + context.replies.push_back(UIEvent { + id: 0, + event_type: UIEventType::StatusNotification(format!( + "Link `{}` not found.", + lidx + )), + }); return; } }; - Command::new("xdg-open") .arg(url) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn() .expect("Failed to start xdg_open"); - - }, - UIEventType::Input(Key::Char('u')) => { //TODO:this should be an Action + } + UIEventType::Input(Key::Char('u')) => { + //TODO:this should be an Action match self.mode { - ViewMode::Normal => { self.mode = ViewMode::Url }, - ViewMode::Url => { self.mode = ViewMode::Normal }, - _ => {}, + ViewMode::Normal => self.mode = ViewMode::Url, + ViewMode::Url => self.mode = ViewMode::Normal, + _ => {} } 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); @@ -309,7 +381,8 @@ impl Component for MailView { } } 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) + 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) } } |