summaryrefslogtreecommitdiffstats
path: root/src/maillist_view.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/maillist_view.rs')
-rw-r--r--src/maillist_view.rs152
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),
+ }
+ }
+
+}
+