summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManos Pitsidianakis <el13635@mail.ntua.gr>2019-06-05 01:24:17 +0300
committerManos Pitsidianakis <el13635@mail.ntua.gr>2019-06-10 19:40:50 +0300
commit831ec97d64ef7aed32f950586cbe20924010af16 (patch)
treef8f2c3858d306dac5efdf404e468ecfbd04cee38
parentd3ce424361adf0b79a0a5f0e2f37d8c7e8c78b5e (diff)
ui: add columns in PlainListing
-rw-r--r--ui/src/components/mail/listing/plain.rs189
1 files changed, 156 insertions, 33 deletions
diff --git a/ui/src/components/mail/listing/plain.rs b/ui/src/components/mail/listing/plain.rs
index 83c9eeaf..e5758356 100644
--- a/ui/src/components/mail/listing/plain.rs
+++ b/ui/src/components/mail/listing/plain.rs
@@ -21,7 +21,48 @@
use super::*;
+use std::cmp;
+use std::ops::{Deref, DerefMut};
const MAX_COLS: usize = 500;
+macro_rules! address_list {
+ (($name:expr) as comma_sep_list) => {{
+ let mut ret: String =
+ $name
+ .into_iter()
+ .fold(String::new(), |mut s: String, n: &Address| {
+ s.extend(n.to_string().chars());
+ s.push_str(", ");
+ s
+ });
+ ret.pop();
+ ret.pop();
+ ret
+ }};
+}
+
+macro_rules! column_str {
+ (
+ struct $name:ident(String)) => {
+ pub struct $name(String);
+
+ impl Deref for $name {
+ type Target = String;
+ fn deref(&self) -> &String {
+ &self.0
+ }
+ }
+ impl DerefMut for $name {
+ fn deref_mut(&mut self) -> &mut String {
+ &mut self.0
+ }
+ }
+ };
+}
+
+column_str!(struct IndexNoString(String));
+column_str!(struct DateString(String));
+column_str!(struct FromString(String));
+column_str!(struct SubjectString(String));
/// A list of all mail (`Envelope`s) in a `Mailbox`. On `\n` it opens the `Envelope` content in a
/// `MailView`.
@@ -69,12 +110,19 @@ impl fmt::Display for PlainListing {
impl PlainListing {
/// Helper function to format entry strings for PlainListing */
/* TODO: Make this configurable */
- fn make_entry_string(e: &Envelope, idx: usize) -> String {
- format!(
- "{} {} {}",
- idx,
- &e.datetime().format("%Y-%m-%d %H:%M:%S").to_string(),
- e.subject()
+ fn make_entry_string(
+ e: &Envelope,
+ idx: usize,
+ ) -> (IndexNoString, FromString, DateString, SubjectString) {
+ (
+ IndexNoString(idx.to_string()),
+ FromString(address_list!((e.from()) as comma_sep_list)),
+ DateString(PlainListing::format_date(e)),
+ SubjectString(format!(
+ "{}{}",
+ e.subject(),
+ if e.has_attachments() { " 📎" } else { "" },
+ )),
)
}
@@ -147,7 +195,56 @@ impl PlainListing {
);
return;
}
+ self.local_collection = account.collection.keys().cloned().collect();
+ let sort = self.sort;
+ self.local_collection.sort_by(|a, b| match sort {
+ (SortField::Date, SortOrder::Desc) => {
+ let ma = &account.get_env(a);
+ let mb = &account.get_env(b);
+ mb.date().cmp(&ma.date())
+ }
+ (SortField::Date, SortOrder::Asc) => {
+ let ma = &account.get_env(a);
+ let mb = &account.get_env(b);
+ ma.date().cmp(&mb.date())
+ }
+ (SortField::Subject, SortOrder::Desc) => {
+ let ma = &account.get_env(a);
+ let mb = &account.get_env(b);
+ ma.subject().cmp(&mb.subject())
+ }
+ (SortField::Subject, SortOrder::Asc) => {
+ let ma = &account.get_env(a);
+ let mb = &account.get_env(b);
+ mb.subject().cmp(&ma.subject())
+ }
+ });
+
+ let mut rows = Vec::with_capacity(1024);
+ let mut min_width = (0, 0, 0);
+ let widths: (usize, usize, usize);
+
+ for idx in 0..self.local_collection.len() {
+ let envelope: &Envelope = &account.get_env(&self.local_collection[idx]);
+ let strings = PlainListing::make_entry_string(envelope, idx);
+ min_width.0 = cmp::max(min_width.0, strings.0.len()); /* index */
+ min_width.1 = cmp::max(min_width.1, strings.2.split_graphemes().len()); /* date */
+ min_width.2 = cmp::max(min_width.2, strings.3.split_graphemes().len()); /* subject */
+ rows.push(strings);
+ }
+ let column_sep: usize = if MAX_COLS >= min_width.0 + min_width.1 + min_width.2 {
+ widths = min_width;
+ 2
+ } else {
+ let width = MAX_COLS - 3 - min_width.0;
+ widths = (
+ min_width.0,
+ cmp::min(min_width.1, width / 3),
+ cmp::min(min_width.2, width / 3),
+ );
+ 1
+ };
// Populate `CellBuffer` with every entry.
let mut idx = 0;
for y in 0..=self.length {
@@ -157,30 +254,6 @@ impl PlainListing {
break;
}
/* Write an entire line for each envelope entry. */
- self.local_collection = account.collection.keys().cloned().collect();
- let sort = self.sort;
- self.local_collection.sort_by(|a, b| match sort {
- (SortField::Date, SortOrder::Desc) => {
- let ma = &account.get_env(a);
- let mb = &account.get_env(b);
- mb.date().cmp(&ma.date())
- }
- (SortField::Date, SortOrder::Asc) => {
- let ma = &account.get_env(a);
- let mb = &account.get_env(b);
- ma.date().cmp(&mb.date())
- }
- (SortField::Subject, SortOrder::Desc) => {
- let ma = &account.get_env(a);
- let mb = &account.get_env(b);
- ma.subject().cmp(&mb.subject())
- }
- (SortField::Subject, SortOrder::Asc) => {
- let ma = &account.get_env(a);
- let mb = &account.get_env(b);
- mb.subject().cmp(&ma.subject())
- }
- });
let envelope: &Envelope = &account.get_env(&self.local_collection[idx]);
let fg_color = if !envelope.is_seen() {
@@ -195,12 +268,48 @@ impl PlainListing {
} else {
Color::Default
};
- let (x, y) = write_string_to_grid(
- &PlainListing::make_entry_string(envelope, idx),
+ let (x, _) = write_string_to_grid(
+ &rows[idx].0,
+ &mut self.content,
+ fg_color,
+ bg_color,
+ ((0, idx), (widths.0, idx)),
+ false,
+ );
+ for x in x..=widths.0 + column_sep {
+ self.content[(x, idx)].set_bg(bg_color);
+ }
+ let mut _x = widths.0 + column_sep;
+ let (mut x, _) = write_string_to_grid(
+ &rows[idx].2,
+ &mut self.content,
+ fg_color,
+ bg_color,
+ ((_x, idx), (widths.1 + _x, idx)),
+ false,
+ );
+ _x += widths.1 + column_sep + 1;
+ for x in x.._x {
+ self.content[(x, idx)].set_bg(bg_color);
+ }
+ let (x, _) = write_string_to_grid(
+ &rows[idx].1,
&mut self.content,
fg_color,
bg_color,
- ((0, y), (MAX_COLS - 1, y)),
+ ((_x, idx), (widths.1 + _x, idx)),
+ false,
+ );
+ _x += widths.1 + column_sep + 2;
+ for x in x.._x {
+ self.content[(x, idx)].set_bg(bg_color);
+ }
+ let (x, _) = write_string_to_grid(
+ &rows[idx].3,
+ &mut self.content,
+ fg_color,
+ bg_color,
+ ((_x, idx), (widths.2 + _x, idx)),
false,
);
@@ -328,6 +437,20 @@ impl PlainListing {
);
context.dirty_areas.push_back(area);
}
+ 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_or_else(|_| std::time::Duration::new(std::u64::MAX, 0));
+ 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))
+ }
+ _ => envelope.datetime().format("%Y-%m-%d %H:%M:%S").to_string(),
+ }
+ }
}
impl Component for PlainListing {