panorama/src/ui/mail_view.rs

231 lines
7.3 KiB
Rust
Raw Normal View History

2021-03-09 11:21:23 +00:00
use std::collections::HashMap;
use std::sync::{
2021-03-20 09:35:41 +00:00
atomic::{AtomicI8, AtomicU32, Ordering},
Arc,
};
2021-03-09 11:21:23 +00:00
2021-03-12 05:07:40 +00:00
use anyhow::Result;
2021-03-09 11:55:31 +00:00
use chrono::{DateTime, Datelike, Duration, Local};
2021-03-09 11:21:23 +00:00
use chrono_humanize::HumanTime;
2021-03-20 08:31:16 +00:00
use crossterm::event::{KeyCode, KeyEvent};
2021-03-09 00:26:18 +00:00
use panorama_imap::response::Envelope;
use tui::{
buffer::Buffer,
layout::{Constraint, Direction, Layout, Rect},
style::{Color, Modifier, Style},
2021-03-08 23:07:44 +00:00
text::{Span, Spans},
widgets::*,
};
use crate::mail::EmailMetadata;
2021-03-20 09:35:41 +00:00
use super::{FrameType, HandlesInput, InputResult, MailStore, TermType, Window, UI};
2021-03-20 09:35:41 +00:00
#[derive(Debug)]
pub struct MailView {
2021-03-20 09:35:41 +00:00
pub mail_store: MailStore,
2021-03-09 00:26:18 +00:00
pub message_list: TableState,
2021-03-20 09:35:41 +00:00
pub selected: Arc<AtomicU32>,
pub change: Arc<AtomicI8>,
2021-03-09 11:21:23 +00:00
}
2021-03-12 05:07:40 +00:00
impl HandlesInput for MailView {
fn handle_key(&mut self, term: TermType, evt: KeyEvent) -> Result<InputResult> {
let KeyEvent { code, .. } = evt;
match code {
// KeyCode::Char('q') => self.0.store(true, Ordering::Relaxed),
// KeyCode::Char('j') => self.1.store(1, Ordering::Relaxed),
// KeyCode::Char('k') => self.1.store(-1, Ordering::Relaxed),
KeyCode::Char(':') => {
// let colon_prompt = Box::new(ColonPrompt::init(term));
// return Ok(InputResult::Push(colon_prompt));
}
_ => {}
}
Ok(InputResult::Ok)
}
}
2021-03-09 11:21:23 +00:00
impl Window for MailView {
fn name(&self) -> String {
String::from("email")
2021-03-09 11:21:23 +00:00
}
fn draw(&self, f: FrameType, area: Rect, ui: &UI) {
2021-03-09 00:26:18 +00:00
let chunks = Layout::default()
.direction(Direction::Horizontal)
.margin(0)
.constraints([Constraint::Length(20), Constraint::Max(5000)])
.split(area);
2021-03-20 09:35:41 +00:00
let accts = self.mail_store.iter_accts();
2021-03-09 00:26:18 +00:00
// folder list
2021-03-20 09:35:41 +00:00
let mut items = vec![];
for acct in accts.iter() {
let result = self.mail_store.folders_of(acct);
if let Some(folders) = result {
items.push(ListItem::new(acct.to_owned()));
for folder in folders {
items.push(ListItem::new(format!(" {}", folder)));
}
}
}
2021-03-09 00:26:18 +00:00
let dirlist = List::new(items)
.block(Block::default().borders(Borders::NONE).title(Span::styled(
2021-03-20 09:35:41 +00:00
"hellosu",
Style::default().add_modifier(Modifier::BOLD),
)))
2021-03-09 00:26:18 +00:00
.style(Style::default().fg(Color::White))
.highlight_style(Style::default().add_modifier(Modifier::ITALIC))
.highlight_symbol(">>");
// message list table
2021-03-20 09:35:41 +00:00
// let mut metas = self
// .message_uids
// .iter()
// .filter_map(|id| self.message_map.get(id))
// .collect::<Vec<_>>();
// metas.sort_by_key(|m| m.date);
// let rows = metas
// .iter()
// .rev()
// .map(|meta| {
// let mut row = Row::new(vec![
// String::from(if meta.unread { "\u{2b24}" } else { "" }),
// meta.uid.map(|u| u.to_string()).unwrap_or_default(),
// meta.date.map(|d| humanize_timestamp(d)).unwrap_or_default(),
// meta.from.clone(),
// meta.subject.clone(),
// ]);
// if meta.unread {
// row = row.style(
// Style::default()
// .fg(Color::LightCyan)
// .add_modifier(Modifier::BOLD),
// );
// }
// row
// })
// .collect::<Vec<_>>();
let mut rows = vec![];
for acct in accts.iter() {
let result = self.mail_store.messages_of(acct);
if let Some(messages) = result {
for meta in messages {
let mut row = Row::new(vec![
String::from(if meta.unread { "\u{2b24}" } else { "" }),
meta.uid.map(|u| u.to_string()).unwrap_or_default(),
meta.date.map(|d| humanize_timestamp(d)).unwrap_or_default(),
meta.from.clone(),
meta.subject.clone(),
]);
if meta.unread {
row = row.style(
Style::default()
.fg(Color::LightCyan)
.add_modifier(Modifier::BOLD),
);
}
rows.push(row);
2021-03-10 11:07:08 +00:00
}
2021-03-20 09:35:41 +00:00
}
}
2021-03-09 00:26:18 +00:00
let table = Table::new(rows)
.style(Style::default().fg(Color::White))
2021-03-09 11:21:23 +00:00
.widths(&[
Constraint::Length(1),
Constraint::Max(3),
Constraint::Min(20),
2021-03-09 11:59:43 +00:00
Constraint::Min(35),
2021-03-09 11:21:23 +00:00
Constraint::Max(5000),
])
.header(
Row::new(vec!["", "UID", "Date", "From", "Subject"])
.style(Style::default().add_modifier(Modifier::BOLD)),
)
.highlight_style(Style::default().bg(Color::DarkGray));
2021-03-09 00:26:18 +00:00
f.render_widget(dirlist, chunks[0]);
f.render_widget(table, chunks[1]);
}
}
2021-03-12 05:07:40 +00:00
/// Turn a timestamp into a format that a human might read when viewing it in a table.
///
/// This means, for dates within the past 24 hours, report it in a relative format.
///
/// For dates sent this year, omit the year entirely.
fn humanize_timestamp(date: DateTime<Local>) -> String {
let now = Local::now();
let diff = now - date;
if diff < Duration::days(1) {
HumanTime::from(date).to_string()
} else if date.year() == now.year() {
date.format("%b %e %T").to_string()
} else {
date.to_rfc2822()
}
}
impl MailView {
2021-03-20 09:35:41 +00:00
pub fn new(mail_store: MailStore) -> Self {
MailView {
mail_store,
message_list: TableState::default(),
selected: Arc::new(AtomicU32::default()),
change: Arc::new(AtomicI8::default()),
}
}
2021-03-20 09:35:41 +00:00
pub fn move_down(&mut self) {
// if self.message_uids.is_empty() {
// return;
// }
// let len = self.message_uids.len();
// if let Some(selected) = self.message_list.selected() {
// if selected + 1 < len {
// self.message_list.select(Some(selected + 1));
// }
// } else {
// self.message_list.select(Some(0));
// }
}
pub fn move_up(&mut self) {
2021-03-20 09:35:41 +00:00
// if self.message_uids.is_empty() {
// return;
// }
// let len = self.message_uids.len();
// if let Some(selected) = self.message_list.selected() {
// if selected >= 1 {
// self.message_list.select(Some(selected - 1));
// }
// } else {
// self.message_list.select(Some(len - 1));
// }
}
pub fn update(&mut self) {
// make the change
if self
.change
.compare_exchange(-1, 0, Ordering::Relaxed, Ordering::Relaxed)
.is_ok()
{
self.move_up();
}
if self
.change
.compare_exchange(1, 0, Ordering::Relaxed, Ordering::Relaxed)
.is_ok()
{
self.move_down();
}
2021-03-09 00:26:18 +00:00
}
}