Add sidebar menu

embed
Manos Pitsidianakis 2018-07-11 23:12:25 +03:00
parent c141496038
commit b11eb1e494
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
6 changed files with 134 additions and 35 deletions

View File

@ -28,6 +28,33 @@ use std::io;
use std::fs;
use std::path::{Path, PathBuf};
#[derive(Debug, Default, Clone)]
pub struct Folder {
name: String,
path: String,
children: Vec<usize>,
}
impl Folder {
fn new(path: String, file_name: String, children: Vec<usize>) -> Self {
Folder {
name: file_name,
path: path,
children: children,
}
}
pub fn get_path(&self) -> &str {
&self.path
}
pub fn get_name(&self) -> &str {
&self.name
}
pub fn get_children(&self) -> &Vec<usize> {
&self.children
}
}
#[derive(Debug, Deserialize)]
struct FileAccount {
folders: String,
@ -43,7 +70,8 @@ struct FileSettings {
#[derive(Debug, Clone)]
pub struct AccountSettings {
pub folders: Vec<String>,
name: String,
pub folders: Vec<Folder>,
format: String,
pub sent_folder: String,
threaded: bool,
@ -53,6 +81,9 @@ impl AccountSettings {
pub fn get_format(&self) -> &str {
&self.format
}
pub fn get_name(&self) -> &str {
&self.name
}
}
#[derive(Debug)]
@ -94,7 +125,8 @@ impl Settings {
for (id, x) in fs.accounts {
let mut folders = Vec::new();
fn recurse_folders<P: AsRef<Path>>(folders: &mut Vec<String>, p: P) {
fn recurse_folders<P: AsRef<Path>>(folders: &mut Vec<Folder>, p: P) -> Vec<usize> {
let mut children = Vec::new();
for mut f in fs::read_dir(p).unwrap() {
for f in f.iter_mut() {
{
@ -105,21 +137,27 @@ impl Settings {
continue;
}
if path.is_dir() {
folders.push(path.to_str().unwrap().to_string());
recurse_folders(folders, path);
let path_children = recurse_folders(folders, &path);
folders.push(Folder::new(path.to_str().unwrap().to_string(), path.file_name().unwrap().to_str().unwrap().to_string(), path_children));
children.push(folders.len()-1);
}
}
}
}
children
};
let path = PathBuf::from(&x.folders);
let path_children = recurse_folders(&mut folders, &path);
if path.is_dir() {
folders.push(path.to_str().unwrap().to_string());
folders.push(Folder::new(path.to_str().unwrap().to_string(), path.file_name().unwrap().to_str().unwrap().to_string(), path_children));
}
recurse_folders(&mut folders, &x.folders);
//recurse_folders(&mut folders, &x.folders);
eprintln!("folders is {:?}", folders);
s.insert(
id.clone(),
AccountSettings {
name: id.clone(),
folders: folders,
format: x.format.to_lowercase(),
sent_folder: x.sent_folder.clone(),

View File

@ -21,7 +21,7 @@
use mailbox::*;
use mailbox::backends::{RefreshEventConsumer, Backends};
use conf::AccountSettings;
use conf::{AccountSettings, Folder};
use std::ops::{Index, IndexMut};
#[derive(Debug)]
@ -42,7 +42,7 @@ impl Account {
let sent_folder = settings
.folders
.iter()
.position(|x| *x == settings.sent_folder);
.position(|x| *x.get_path() == settings.sent_folder);
let mut folders = Vec::with_capacity(settings.folders.len());
for _ in 0..settings.folders.len() {
folders.push(None);
@ -59,15 +59,18 @@ impl Account {
}
}
pub fn watch(&self, r: RefreshEventConsumer) -> () {
self.backend.watch(r, &self.settings.folders);
self.backend.watch(r, &self.settings.folders[..]);
}
/* This doesn't represent the number of correctly parsed mailboxes though */
pub fn len(&self) -> usize {
self.folders.len()
}
pub fn list_folders(&self) -> Vec<String> {
pub fn list_folders(&self) -> Vec<Folder> {
self.settings.folders.clone()
}
pub fn get_name(&self) -> &str {
&self.name
}
}
impl Index<usize> for Account {
@ -81,12 +84,13 @@ impl IndexMut<usize> for Account {
fn index_mut(&mut self, index: usize) -> &mut Option<Result<Mailbox>> {
if self.folders[index].is_none() {
eprintln!("building folder {:?}", self.settings.folders[index]);
let path = self.settings.folders[index].clone();
let folder = &self.settings.folders[index];
let path = folder.get_path().clone();
if self.sent_folder.is_some() {
let id = self.sent_folder.unwrap();
if id == index {
eprintln!("building sent_folder..");
self.folders[index] = Some(Mailbox::new(&path, &None, self.backend.get(&path)));
self.folders[index] = Some(Mailbox::new(folder, &None, self.backend.get(&folder)));
eprintln!("Done!");
} else {
eprintln!(
@ -103,13 +107,13 @@ impl IndexMut<usize> for Account {
)
}
};
let sent_path = self.settings.folders[id].clone();
let sent_path = &self.settings.folders[id];
if sent[0].is_none() {
eprintln!("\tbuilding sent_folder..");
sent[0] = Some(Mailbox::new(&sent_path, &None, self.backend.get(&path)));
sent[0] = Some(Mailbox::new(sent_path, &None, self.backend.get(&folder)));
eprintln!("\tDone!");
}
cur[0] = Some(Mailbox::new(&path, &sent[0],self.backend.get(&path)));
cur[0] = Some(Mailbox::new(folder, &sent[0],self.backend.get(folder)));
eprintln!("Done!");
}
} else {
@ -117,7 +121,7 @@ impl IndexMut<usize> for Account {
"Now building folder {:?} without sent_folder",
self.settings.folders[index]
);
self.folders[index] = Some(Mailbox::new(&path, &None,self.backend.get(&path)));
self.folders[index] = Some(Mailbox::new(folder, &None,self.backend.get(&folder)));
eprintln!("Done!");
};
}

View File

@ -23,6 +23,7 @@ use mailbox::email::{Envelope, Flag};
use error::{MeliError, Result};
use mailbox::backends::{BackendOp, BackendOpGenerator, MailBackend, RefreshEvent, RefreshEventConsumer};
use mailbox::email::parser;
use conf::Folder;
extern crate notify;
@ -122,8 +123,8 @@ pub struct MaildirType {
impl MailBackend for MaildirType {
fn get(&self, path: &str) -> Result<Vec<Envelope>> {
self.get_multicore(4, path)
fn get(&self, folder: &Folder) -> Result<Vec<Envelope>> {
self.get_multicore(4, folder)
/*
MaildirType::is_valid(&self.path)?;
@ -146,7 +147,7 @@ impl MailBackend for MaildirType {
Ok(r)
*/
}
fn watch(&self, sender: RefreshEventConsumer, folders: &[String]) -> () {
fn watch(&self, sender: RefreshEventConsumer, folders: &[Folder]) -> () {
let folders = folders.to_vec();
thread::Builder::new().name("folder watch".to_string()).spawn(move || {
@ -156,7 +157,7 @@ impl MailBackend for MaildirType {
if MaildirType::is_valid(&f).is_err() {
continue;
}
let mut p = PathBuf::from(&f);
let mut p = PathBuf::from(&f.get_path());
p.push("cur");
watcher.watch(&p, RecursiveMode::NonRecursive).unwrap();
p.pop();
@ -182,7 +183,8 @@ impl MaildirType {
path: path.to_string(),
}
}
fn is_valid(path: &str) -> Result<()> {
fn is_valid(f: &Folder) -> Result<()> {
let path = f.get_path();
let mut p = PathBuf::from(path);
for d in &["cur", "new", "tmp"] {
p.push(d);
@ -195,8 +197,9 @@ impl MaildirType {
}
Ok(())
}
pub fn get_multicore(&self, cores: usize, path: &str) -> Result<Vec<Envelope>> {
MaildirType::is_valid(path)?;
pub fn get_multicore(&self, cores: usize, folder: &Folder) -> Result<Vec<Envelope>> {
MaildirType::is_valid(folder)?;
let path = folder.get_path();
let mut path = PathBuf::from(path);
path.push("cur");
let iter = path.read_dir()?;

View File

@ -20,6 +20,7 @@
*/
pub mod maildir;
use conf::Folder;
use mailbox::email::{Envelope, Flag};
use mailbox::backends::maildir::MaildirType;
use error::Result;
@ -79,8 +80,8 @@ impl RefreshEventConsumer {
}
}
pub trait MailBackend: ::std::fmt::Debug {
fn get(&self, path: &str) -> Result<Vec<Envelope>>;
fn watch(&self, sender:RefreshEventConsumer, folders: &[String]) -> ();
fn get(&self, folder: &Folder) -> Result<Vec<Envelope>>;
fn watch(&self, sender:RefreshEventConsumer, folders: &[Folder]) -> ();
//fn new(folders: &Vec<String>) -> Box<Self>;
//login function
}

View File

@ -30,13 +30,15 @@ pub use mailbox::accounts::Account;
pub mod thread;
pub use mailbox::thread::{build_threads, Container};
use conf::Folder;
use std::option::Option;
/// `Mailbox` represents a folder of mail.
#[derive(Debug, Clone)]
pub struct Mailbox {
pub path: String,
pub folder: Folder,
pub collection: Vec<Envelope>,
pub threaded_collection: Vec<usize>,
threads: Vec<Container>,
@ -46,18 +48,18 @@ pub struct Mailbox {
impl Mailbox {
pub fn new_dummy() -> Self {
Mailbox {
path: String::default(),
folder: Folder::default(),
collection: Vec::with_capacity(0),
threaded_collection: Vec::with_capacity(0),
threads: Vec::with_capacity(0),
}
}
pub fn new(path: &str, sent_folder: &Option<Result<Mailbox>>, collection: Result<Vec<Envelope>>) -> Result<Mailbox> {
pub fn new(folder: &Folder, sent_folder: &Option<Result<Mailbox>>, collection: Result<Vec<Envelope>>) -> Result<Mailbox> {
let mut collection: Vec<Envelope> = collection?;
collection.sort_by(|a, b| a.get_date().cmp(&b.get_date()));
let (threads, threaded_collection) = build_threads(&mut collection, sent_folder);
Ok(Mailbox {
path: path.to_string(),
folder: folder.clone(),
collection: collection,
threads: threads,
threaded_collection: threaded_collection,

View File

@ -48,7 +48,8 @@ impl MailListing {
/// Draw only the list of `Envelope`s.
fn draw_list(&mut self, grid: &mut CellBuffer, upper_left: Pos, bottom_right: Pos) {
if self.length == 0 {
write_string_to_grid(&format!("Folder `{}` is empty.", self.mailbox.path), grid, Color::Default, Color::Default, upper_left, upper_left);
clear_area(grid, upper_left, bottom_right);
write_string_to_grid(&format!("Folder `{}` is empty.", self.mailbox.folder.get_name()), grid, Color::Default, Color::Default, upper_left, upper_left);
return;
}
/* If cursor position has changed, remove the highlight from the previous position and
@ -228,8 +229,9 @@ impl Component for MailListing {
#[derive(Debug)]
pub struct AccountMenu {
entries: Vec<(usize, String)>,
entries: Vec<(usize, Folder)>,
dirty: bool,
name: String,
}
@ -237,30 +239,79 @@ impl AccountMenu {
pub fn new(account: &Account) -> Self{
let mut entries = Vec::with_capacity(account.len());
for (idx, acc) in account.list_folders().iter().enumerate() {
eprintln!("acc[{}] is {:?}", idx, acc);
entries.push((idx, acc.clone()));
}
AccountMenu {
entries: entries,
dirty: true,
name: account.get_name().to_string(),
}
}
}
impl Component for AccountMenu {
fn draw(&mut self, grid: &mut CellBuffer, upper_left: Pos, bottom_right: Pos) {
eprintln!("reached accountmenu draw {:?}", self);
if !(self.dirty) {
return;
}
self.dirty = false;
let mut parents: Vec<Option<usize>> = vec!(None; self.entries.len());
for (idx, e) in self.entries.iter().enumerate() {
for c in e.1.get_children() {
parents[*c] = Some(idx);
}
}
let mut roots = Vec::new();
for (idx, c) in parents.iter().enumerate() {
if c.is_none() {
roots.push(idx);
}
}
let mut ind = 0;
let mut depth = String::from("");
let mut s = String::from(format!("{}\n", self.name));
fn pop(depth: &mut String) {
depth.pop();
depth.pop();
depth.pop();
depth.pop();
}
fn push(depth: &mut String, c: char) {
depth.push(' ');
depth.push(c);
depth.push(' ');
depth.push(' ');
}
fn print(root: usize, parents: &Vec<Option<usize>>, depth: &mut String, entries: &Vec<(usize, Folder)>, mut s: String) -> String {
let len = s.len();
s.insert_str(len, &format!("{}: {}\n", &entries[root].1.get_name(), entries[root].0));
let children_no = entries[root].1.get_children().len();
for (idx, child) in entries[root].1.get_children().iter().enumerate() {
let len = s.len();
s.insert_str(len, &format!("{}├─", depth));
push(depth, if idx == children_no - 1 {'│'} else { ' ' });
s = print(*child, parents, depth, entries, s);
pop(depth);
}
s
}
for r in roots {
s =print(r, &parents, &mut depth, &self.entries, s);
}
let lines: Vec<&str> = s.lines().collect();
let mut idx = 0;
for y in get_y(upper_left)..get_y(bottom_right) {
if idx == self.entries.len() {
break;
}
let s = format!("{:?}",self.entries[idx]);
eprintln!("wrote {} to menu", s);
let s = format!("{}", lines[idx]);
write_string_to_grid(&s, grid, Color::Red, Color::Default, set_y(upper_left, y), bottom_right);
idx += 1;
}