Add sidebar menu
parent
c141496038
commit
b11eb1e494
|
@ -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(),
|
||||
|
|
|
@ -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!");
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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()?;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue