summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2020-07-23 14:08:10 +0200
committerMatthias Beyer <mail@beyermatthias.de>2020-07-23 14:47:06 +0200
commite49a3bff3c47ae38494ca5e24da5bb23793699ff (patch)
treedfb67d8d8a9347e5963263b67585c281f99b59ec /src
parent7ef4c57e20153d5082d179645fb550060a6704fc (diff)
Outsource mailinglist view code
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
Diffstat (limited to 'src')
-rw-r--r--src/maillist_view.rs161
-rw-r--r--src/main.rs1
-rw-r--r--src/main_view.rs95
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),
- }
- }
-
-}
-