diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2020-07-23 14:08:10 +0200 |
---|---|---|
committer | Matthias Beyer <mail@beyermatthias.de> | 2020-07-23 14:47:06 +0200 |
commit | e49a3bff3c47ae38494ca5e24da5bb23793699ff (patch) | |
tree | dfb67d8d8a9347e5963263b67585c281f99b59ec /src | |
parent | 7ef4c57e20153d5082d179645fb550060a6704fc (diff) |
Outsource mailinglist view code
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
Diffstat (limited to 'src')
-rw-r--r-- | src/maillist_view.rs | 161 | ||||
-rw-r--r-- | src/main.rs | 1 | ||||
-rw-r--r-- | src/main_view.rs | 95 |
3 files changed, 165 insertions, 92 deletions
diff --git a/src/maillist_view.rs b/src/maillist_view.rs new file mode 100644 index 0000000..b955b1f --- /dev/null +++ b/src/maillist_view.rs @@ -0,0 +1,161 @@ +use std::ops::Deref; +use std::ops::DerefMut; +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: crate::mail::UnparsedMail::read_from_path(msg.id().to_string(), msg.filename())?, + 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<_>>>()?; + + 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, index: 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 Deref for MaillistView { + type Target = TableView<MailListingData, MailListingColumn>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +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: crate::mail::UnparsedMail, + 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), + } + } + +} + diff --git a/src/main.rs b/src/main.rs index d11f394..8de716c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ use cursive::CursiveExt; use cursive::event::{Event, EventTrigger}; mod main_view; +mod maillist_view; mod mail; mod configuration; diff --git a/src/main_view.rs b/src/main_view.rs index b4e0bd0..a8b5c27 100644 --- a/src/main_view.rs +++ b/src/main_view.rs @@ -21,6 +21,7 @@ use cursive_table_view::TableColumn; use cursive_tabs::TabPanel; use crate::configuration::Configuration; +use crate::maillist_view::MaillistView; pub const MAIN_VIEW_NAME: &'static str = "main_view"; pub const MAIN_MAIL_LIST_NAME: &'static str = "main_mail_list"; @@ -96,106 +97,16 @@ impl MainView { .with_tab(config.notmuch_default_query().clone(), { ResizedView::new(cursive::view::SizeConstraint::Full, cursive::view::SizeConstraint::Full, - MainView::main_mail_list(&config)?) + MaillistView::create_for(config.notmuch_database_path(), config.notmuch_default_query(), MAIN_MAIL_LIST_NAME.to_string())? + .with_name(MAIN_MAIL_LIST_NAME)) }); Ok(MainView { tabs }.with_name(MAIN_VIEW_NAME)) } - fn main_mail_list(config: &Configuration) -> Result<NamedView<TableView<MailListingData, MailListingColumn>>> { - let query = config.notmuch_default_query(); - let datab = config.notmuch_database_path(); - - debug!("Getting '{}' from '{}'", query, datab.display()); - - let items = notmuch::Database::open(datab, notmuch::DatabaseMode::ReadOnly)? - .create_query(query)? - .search_messages()? - .map(|msg| { - Ok(MailListingData { - mail: crate::mail::UnparsedMail::read_from_path(msg.id().to_string(), msg.filename())?, - 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<_>>>()?; - - 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, index: usize| { - let mail_id = siv.call_on_name(&MAIN_MAIL_LIST_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(tab.with_name(MAIN_MAIL_LIST_NAME)) - } - pub fn add_tab<T: View>(&mut self, id: String, view: T) { self.tabs.add_tab(id, view) } } -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub enum MailListingColumn { - Date, - Tags, - From, - To, - Subject, -} - -#[derive(Clone, Debug)] -pub struct MailListingData { - mail: crate::mail::UnparsedMail, - 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), - } - } - -} - |