diff options
Diffstat (limited to 'src/maillist_view.rs')
-rw-r--r-- | src/maillist_view.rs | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/src/maillist_view.rs b/src/maillist_view.rs new file mode 100644 index 0000000..97afff7 --- /dev/null +++ b/src/maillist_view.rs @@ -0,0 +1,152 @@ +use std::path::PathBuf; + +use anyhow::Result; +use cursive::Cursive; +use cursive::Printer; +use cursive::Rect; +use cursive::View; +use cursive::XY; +use cursive::direction::Direction; +use cursive::view::Selector; +use cursive::event::Event; +use cursive::event::EventResult; +use cursive::views::ResizedView; +use cursive_table_view::TableView; +use cursive_table_view::TableViewItem; + +pub struct MaillistView(TableView<MailListingData, MailListingColumn>); + +impl MaillistView { + pub fn create_for(database_path: &PathBuf, query: &str, name: String) -> Result<Self> { + debug!("Getting '{}' from '{}'", query, database_path.display()); + + let items = notmuch::Database::open(database_path, notmuch::DatabaseMode::ReadOnly)? + .create_query(query)? + .search_messages()? + .map(|msg| { + Ok(MailListingData { + mail_id: msg.id().to_string(), + tags: msg.tags().collect(), + date: chrono::naive::NaiveDateTime::from_timestamp_opt(msg.date(), 0) + .ok_or_else(|| anyhow!("Failed to parse timestamp: {}", msg.date()))? + .to_string(), + + from: msg.header("From")?.ok_or_else(|| anyhow!("Failed to get From for {}", msg.id()))?.to_string(), + to: msg.header("To")?.map(|c| c.to_string()).unwrap_or_else(|| String::from("")), + subject: msg.header("Subject")?.ok_or_else(|| anyhow!("Failed to get Subject for {}", msg.id()))?.to_string(), + }) + }) + .collect::<Result<Vec<_>>>()?; + + debug!("Found {} entries", items.len()); + let tab = TableView::<MailListingData, MailListingColumn>::new() + .column(MailListingColumn::Date, "Date", |c| c.width(20)) + .column(MailListingColumn::Tags, "Tags", |c| c.width(20)) + .column(MailListingColumn::From, "From", |c| c) + .column(MailListingColumn::To, "To", |c| c) + .column(MailListingColumn::Subject, "Subject", |c| c) + .default_column(MailListingColumn::Date) + .items(items) + .selected_item(0) + .on_submit(move |siv: &mut Cursive, row: usize, _: usize| { + let mail_id = siv.call_on_name(&name, move |table: &mut ResizedView<TableView<MailListingData, MailListingColumn>>| { + table.get_inner_mut() + .borrow_item(row) + .map(|data| data.mail_id.clone()) + }); + + // use the mail ID to get the whole thread and open it as a table item + }); + + Ok(MaillistView(tab)) + } +} + +impl View for MaillistView { + fn draw(&self, printer: &Printer) { + self.0.draw(printer) + } + + fn layout(&mut self, xy: XY<usize>) { + self.0.layout(xy) + } + + fn needs_relayout(&self) -> bool { + self.0.needs_relayout() + } + + fn required_size(&mut self, constraint: XY<usize>) -> XY<usize> { + self.0.required_size(constraint) + } + + fn on_event(&mut self, e: Event) -> EventResult { + self.0.on_event(e) + } + + fn call_on_any<'a>(&mut self, s: &Selector, tpl: &'a mut (dyn FnMut(&mut (dyn View + 'static)) + 'a)) { + self.0.call_on_any(s, tpl); + } + + fn focus_view(&mut self, s: &Selector) -> Result<(), ()> { + self.0.focus_view(s) + } + + fn take_focus(&mut self, source: Direction) -> bool { + self.0.take_focus(source) + } + + fn important_area(&self, view_size: XY<usize>) -> Rect { + self.0.important_area(view_size) + } + + fn type_name(&self) -> &'static str { + self.0.type_name() + } + +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub enum MailListingColumn { + Date, + Tags, + From, + To, + Subject, +} + +#[derive(Clone, Debug)] +pub struct MailListingData { + mail_id: String, + tags: Vec<String>, + date: String, + from: String, + to: String, + subject: String, +} + +impl TableViewItem<MailListingColumn> for MailListingData { + + fn to_column(&self, column: MailListingColumn) -> String { + match column { + MailListingColumn::Date => self.date.clone(), + MailListingColumn::Tags => self.tags.join(", "), + MailListingColumn::From => self.from.clone(), + MailListingColumn::To => self.to.clone(), + MailListingColumn::Subject => self.subject.clone(), + } + } + + fn cmp(&self, other: &Self, column: MailListingColumn) -> std::cmp::Ordering + where Self: Sized + { + match column { + MailListingColumn::Date => self.date.cmp(&other.date), + MailListingColumn::Tags => self.tags.cmp(&other.tags), + MailListingColumn::From => self.from.cmp(&other.from), + MailListingColumn::To => self.to.cmp(&other.to), + MailListingColumn::Subject => self.subject.cmp(&other.subject), + } + } + +} + |