From 4cf5e76ed4c2d5b179e166628295e0a09a022aaf Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 5 Jul 2020 13:28:18 +0200 Subject: Add main view implementation This patch adds a main view that can be used to list mails from boxes. Signed-off-by: Matthias Beyer --- Cargo.toml | 5 +++ src/main.rs | 30 +++-------------- src/main_view.rs | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/sidebar.rs | 34 +++++++++++++++----- 4 files changed, 134 insertions(+), 33 deletions(-) create mode 100644 src/main_view.rs diff --git a/Cargo.toml b/Cargo.toml index 4b34c61..3259871 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,3 +16,8 @@ cursive = "0.15" [dependencies.cursive_tree_view] git = "https://github.com/matthiasbeyer/cursive_tree_view" branch = "update-deps" + +[dependencies.cursive-tabs] +git = "https://github.com/matthiasbeyer/cursive-tabs" +branch = "update-deps" + diff --git a/src/main.rs b/src/main.rs index 646a9fe..04f041d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,30 +3,12 @@ use std::path::PathBuf; use anyhow::Result; use cursive::CursiveExt; -use cursive::view::Nameable; use mailparse::MailHeaderMap; use mailparse::ParsedMail; mod mailstore; mod sidebar; - -fn list_view_for<'a, I>(i: I) -> Result - where I: Iterator -{ - let mut lv = cursive::views::ListView::new(); - - for elem in i { - let s = format!("{}: {} -> {} | {}", - elem.headers.get_first_value("Date").unwrap_or_else(|| String::from("No date")), - elem.headers.get_first_value("From").unwrap_or_else(|| String::from("No From")), - elem.headers.get_first_value("To").unwrap_or_else(|| String::from("No To")), - elem.headers.get_first_value("Subject").unwrap_or_else(|| String::from("No Subject"))); - - lv.add_child("", cursive::views::TextView::new(s)); - } - - Ok(lv) -} +mod main_view; fn main() -> Result<()> { let maildir_path = std::env::args() @@ -36,7 +18,7 @@ fn main() -> Result<()> { .ok_or_else(|| anyhow!("No path to maildir passed"))?; let dirs = walkdir::WalkDir::new(maildir_path.clone()) - .max_depth(0) + .max_depth(1) .follow_links(false) .same_file_system(true) .into_iter() @@ -45,13 +27,11 @@ fn main() -> Result<()> { .map(|de| de.path().to_path_buf()); let sidebar = sidebar::sidebar(dirs)?; - let mut md = mailstore::MailStore::from_path(maildir_path); - md.load()?; - let list_view = list_view_for(md.cur_mail().iter().map(mailstore::Mail::parsed))?; + let mainview = main_view::MainView::new(); let mut layout = cursive::views::LinearLayout::horizontal(); - layout.add_child(sidebar.with_name("Sidebar")); - layout.add_child(list_view); + layout.add_child(sidebar); + layout.add_child(mainview); let mut siv = cursive::Cursive::default(); siv.add_layer(layout); diff --git a/src/main_view.rs b/src/main_view.rs new file mode 100644 index 0000000..9c92a7e --- /dev/null +++ b/src/main_view.rs @@ -0,0 +1,98 @@ +use std::path::PathBuf; +use anyhow::Result; +use cursive::{View, Printer, XY, direction::Direction, view::Selector, Rect, event::Event, event::EventResult}; +use cursive::view::Nameable; +use cursive::Cursive; +use cursive::views::NamedView; +use mailparse::MailHeaderMap; +use mailparse::ParsedMail; + +use crate::mailstore::{ MailStore, Mail }; + +pub const MAIN_VIEW_NAME: &'static str = "main_view"; + +pub struct MainView { + tabs: cursive_tabs::TabView, +} + +impl View for MainView { + fn draw(&self, printer: &Printer) { + self.tabs.draw(printer) + } + + fn layout(&mut self, xy: XY) { + self.tabs.layout(xy) + } + + fn needs_relayout(&self) -> bool { + self.tabs.needs_relayout() + } + + fn required_size(&mut self, constraint: XY) -> XY { + self.tabs.required_size(constraint) + } + + fn on_event(&mut self, e: Event) -> EventResult { + self.tabs.on_event(e) + } + + fn call_on_any<'a>(&mut self, s: &Selector, tpl: &'a mut (dyn FnMut(&mut (dyn View + 'static)) + 'a)) { + self.tabs.call_on_any(s, tpl); + } + + fn focus_view(&mut self, s: &Selector) -> Result<(), ()> { + self.tabs.focus_view(s) + } + + fn take_focus(&mut self, source: Direction) -> bool { + self.tabs.take_focus(source) + } + + fn important_area(&self, view_size: XY) -> Rect { + self.tabs.important_area(view_size) + } + + fn type_name(&self) -> &'static str { + self.tabs.type_name() + } + +} + +impl MainView { + pub fn new() -> NamedView { + let mut tabs = cursive_tabs::TabView::default(); + tabs.add_tab(0, cursive::views::TextView::new("Test")); + MainView { tabs }.with_name(MAIN_VIEW_NAME) + } + + pub fn load_maildir(&mut self, pb: PathBuf) -> Result<()> { + let mut md = MailStore::from_path(pb); + md.load()?; + let list_view = MainView::list_view_for(md.cur_mail().iter().map(Mail::parsed))?; + + self.tabs.add_tab(1, list_view.with_name("Tab")); + Ok(()) + } + + fn list_view_for<'a, I>(i: I) -> Result + where I: Iterator + { + let mut lv = cursive::views::ListView::new(); + + for elem in i { + let s = format!("{}: {} -> {} | {}", + elem.headers.get_first_value("Date").unwrap_or_else(|| String::from("No date")), + elem.headers.get_first_value("From").unwrap_or_else(|| String::from("No From")), + elem.headers.get_first_value("To").unwrap_or_else(|| String::from("No To")), + elem.headers.get_first_value("Subject").unwrap_or_else(|| String::from("No Subject"))); + + lv.add_child("", cursive::views::TextView::new(s)); + } + + Ok(lv) + } + +} + + + diff --git a/src/sidebar.rs b/src/sidebar.rs index ecc2e29..922e446 100644 --- a/src/sidebar.rs +++ b/src/sidebar.rs @@ -2,11 +2,17 @@ use std::path::PathBuf; use anyhow::Result; use std::fmt; use std::ffi::OsStr; +use cursive::view::Nameable; +use cursive::views::NamedView; +use cursive::Cursive; + +use crate::main_view::MainView; +use cursive_tree_view::TreeView; #[derive(Debug)] pub struct TreeEntry { name: String, - dir: Option, + path: PathBuf, } impl fmt::Display for TreeEntry { @@ -15,23 +21,34 @@ impl fmt::Display for TreeEntry { } } +pub const SIDEBAR_VIEW_NAME: &'static str = "sidebar_tree_view"; -pub fn sidebar(iter: I) -> Result> +pub fn sidebar(iter: I) -> Result>> where I: Iterator { let mut tv = cursive_tree_view::TreeView::default(); + tv.set_on_submit(|siv: &mut Cursive, row: usize| { + let borrow = siv.call_on_name(SIDEBAR_VIEW_NAME, move |tree: &mut TreeView| { + tree.borrow_item(row).map(|b| b.path.clone()) + }) + .flatten(); + + if let Some(path) = borrow { + siv.call_on_name(crate::main_view::MAIN_VIEW_NAME, move |main_view: &mut MainView| { + main_view.load_maildir(path); + None as Option<()> + }); + } + }); + + // Fill the tree from the iterator iter.map(|path| { path.file_name() .and_then(OsStr::to_str) .map(String::from) .ok_or_else(|| anyhow!("UTF8 error")) - .map(|name| { - TreeEntry { - name, - dir: Some(path) - } - }) + .map(|name| TreeEntry { name, path }) }) .enumerate() .fold(Ok(tv), |accu, (i, item)| { @@ -40,4 +57,5 @@ pub fn sidebar(iter: I) -> Result> .map(|_| tv) }) }) + .map(|tv| tv.with_name(SIDEBAR_VIEW_NAME)) } -- cgit v1.2.3