Make date printing prettier in entry formatting

embed
Manos Pitsidianakis 2018-07-22 11:14:23 +03:00
parent 00235fe814
commit a7993d48f8
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
3 changed files with 230 additions and 202 deletions

View File

@ -141,7 +141,7 @@ pub struct Envelope {
references: Option<References>, references: Option<References>,
datetime: Option<chrono::DateTime<chrono::FixedOffset>>, datetime: Option<chrono::DateTime<chrono::FixedOffset>>,
timestamp: i64, timestamp: u64,
thread: usize, thread: usize,
operation_token: Arc<Box<BackendOpGenerator>>, operation_token: Arc<Box<BackendOpGenerator>>,
@ -254,9 +254,10 @@ if let Some(ref mut d) = datetime {
} }
} }
} }
pub fn date(&self) -> i64 { pub fn date(&self) -> u64 {
self.timestamp self.timestamp
} }
pub fn datetime(&self) -> chrono::DateTime<chrono::FixedOffset> { pub fn datetime(&self) -> chrono::DateTime<chrono::FixedOffset> {
self.datetime.unwrap_or_else(|| { self.datetime.unwrap_or_else(|| {
chrono::FixedOffset::west(0) chrono::FixedOffset::west(0)
@ -345,7 +346,7 @@ fn set_to(&mut self, new_val: String) -> () {
fn set_in_reply_to(&mut self, new_val: &str) -> () { fn set_in_reply_to(&mut self, new_val: &str) -> () {
let slice = match parser::message_id(new_val.as_bytes()).to_full_result() { let slice = match parser::message_id(new_val.as_bytes()).to_full_result() {
Ok(v) => v, Ok(v) => v,
Err(v) => { Err(_) => {
self.in_reply_to = None; self.in_reply_to = None;
return; return;
} }
@ -358,7 +359,7 @@ fn set_subject(&mut self, new_val: String) -> () {
fn set_message_id(&mut self, new_val: &str) -> () { fn set_message_id(&mut self, new_val: &str) -> () {
let slice = match parser::message_id(new_val.as_bytes()).to_full_result() { let slice = match parser::message_id(new_val.as_bytes()).to_full_result() {
Ok(v) => v, Ok(v) => v,
Err(v) => { Err(_) => {
self.message_id = None; self.message_id = None;
return; return;
} }
@ -368,7 +369,7 @@ fn set_message_id(&mut self, new_val: &str) -> () {
fn push_references(&mut self, new_val: &str) -> () { fn push_references(&mut self, new_val: &str) -> () {
let slice = match parser::message_id(new_val.as_bytes()).to_full_result() { let slice = match parser::message_id(new_val.as_bytes()).to_full_result() {
Ok(v) => v, Ok(v) => v,
Err(v) => { Err(_) => {
return; return;
} }
}; };
@ -434,7 +435,7 @@ pub fn set_thread(&mut self, new_val: usize) -> () {
} }
pub fn set_datetime(&mut self, new_val: chrono::DateTime<chrono::FixedOffset>) -> () { pub fn set_datetime(&mut self, new_val: chrono::DateTime<chrono::FixedOffset>) -> () {
self.datetime = Some(new_val); self.datetime = Some(new_val);
self.timestamp = new_val.timestamp(); self.timestamp = new_val.timestamp() as u64;
} }
pub fn flags(&self) -> Flag { pub fn flags(&self) -> Flag {
self.flags self.flags

View File

@ -27,9 +27,7 @@ extern crate fnv;
use self::fnv::FnvHashMap; use self::fnv::FnvHashMap;
use std; use std;
type UnixTimestamp = u64;
type UnixTimestamp = i64;
/// A `Container` struct is needed to describe the thread tree forest during creation of threads. /// A `Container` struct is needed to describe the thread tree forest during creation of threads.
/// Because of Rust's memory model, we store indexes of Envelopes inside a collection instead of /// Because of Rust's memory model, we store indexes of Envelopes inside a collection instead of

View File

@ -54,7 +54,6 @@ impl MailListing {
self.length = if threaded { self.length = if threaded {
mailbox.threaded_collection.len() mailbox.threaded_collection.len()
} else { } else {
mailbox.len() mailbox.len()
}; };
@ -75,17 +74,23 @@ impl MailListing {
// TODO: Fix the threaded hell and refactor stuff into seperate functions and/or modules. // TODO: Fix the threaded hell and refactor stuff into seperate functions and/or modules.
if threaded { if threaded {
let mut indentations: Vec<bool> = Vec::with_capacity(6); let mut indentations: Vec<bool> = Vec::with_capacity(6);
let mut thread_idx = 0; // needed for alternate thread colors
/* Draw threaded view. */ /* Draw threaded view. */
let mut iter = mailbox let mut iter = mailbox
.threaded_collection .threaded_collection
.iter() .iter()
.enumerate() .enumerate()
.peekable(); .peekable();
let len = mailbox.threaded_collection.len().to_string().chars().count();
/* This is just a desugared for loop so that we can use .peek() */ /* This is just a desugared for loop so that we can use .peek() */
while let Some((idx, i)) = iter.next() { while let Some((idx, i)) = iter.next() {
let container = mailbox.thread(*i); let container = mailbox.thread(*i);
let indentation = container.indentation(); let indentation = container.indentation();
if indentation == 0 {
thread_idx += 1;
}
assert_eq!(container.has_message(), true); assert_eq!(container.has_message(), true);
match iter.peek() { match iter.peek() {
Some(&(_, x)) Some(&(_, x))
@ -111,12 +116,12 @@ impl MailListing {
}; };
let bg_color = if !envelope.is_seen() { let bg_color = if !envelope.is_seen() {
Color::Byte(251) Color::Byte(251)
} else if idx % 2 == 0 { } else if thread_idx % 2 == 0 {
Color::Byte(236) Color::Byte(236)
} else { } else {
Color::Default Color::Default
}; };
let (x, y) = write_string_to_grid(&MailListing::make_thread_entry(envelope, idx, indentation, container, &indentations), let (x, y) = write_string_to_grid(&MailListing::make_thread_entry(envelope, idx, indentation, container, &indentations, len),
&mut content, &mut content,
fg_color, fg_color,
bg_color, bg_color,
@ -280,12 +285,12 @@ impl MailListing {
self.pager.as_mut().map(|p| p.draw(grid, area, context)); self.pager.as_mut().map(|p| p.draw(grid, area, context));
} }
fn make_thread_entry(envelope: &Envelope, idx: usize, indent: usize, fn make_thread_entry(envelope: &Envelope, idx: usize, indent: usize,
container: &Container, indentations: &Vec<bool>) -> String { container: &Container, indentations: &Vec<bool>, idx_width: usize) -> String {
let has_sibling = container.has_sibling(); let has_sibling = container.has_sibling();
let has_parent = container.has_parent(); let has_parent = container.has_parent();
let show_subject = container.show_subject(); let show_subject = container.show_subject();
let mut s = format!("{} {} ", idx, &envelope.datetime().format("%Y-%m-%d %H:%M:%S").to_string()); let mut s = format!("{}{}{} ", idx, " ".repeat(idx_width + 2 - (idx.to_string().chars().count())), MailListing::format_date(&envelope));
for i in 0..indent { for i in 0..indent {
if indentations.len() > i && indentations[i] if indentations.len() > i && indentations[i]
{ {
@ -307,13 +312,37 @@ impl MailListing {
} }
s.push('─'); s.push('>'); s.push('─'); s.push('>');
} }
s.push_str(&format!(" {}", envelope.body().count_attachments()));
if show_subject { if show_subject {
s.push_str(&format!("{:.85}", envelope.subject())); s.push_str(&format!("{:.85}", envelope.subject()));
} }
let attach_count = envelope.body().count_attachments();
if attach_count > 0 {
s.push_str(&format!(" {}", attach_count));
}
s s
} }
fn format_date(envelope: &Envelope) -> String {
let d = std::time::UNIX_EPOCH + std::time::Duration::from_secs(envelope.date());
let now: std::time::Duration = std::time::SystemTime::now().duration_since(d).unwrap();
match now.as_secs() {
n if n < 10*60*60 => {
format!("{} hours ago{}", n / (60*60), " ".repeat(8))
},
n if n < 24*60*60 => {
format!("{} hours ago{}", n / (60*60), " ".repeat(7))
},
n if n < 4*24*60*60 => {
format!("{} days ago{}", n / (24*60*60), " ".repeat(9))
},
_ => {
let date = envelope.datetime();
envelope.datetime().format("%Y-%m-%d %H:%M:%S").to_string()
},
}
}
} }
impl Component for MailListing { impl Component for MailListing {