ui: add triptych thread mailing view

This mail list view shows one entry per thread just like CompactListing,
but the entry is slightly bigger just like in some GUIs, and when the
thread is opened the view becomes 3 columned:

+--+-------+----+
|~~|-------|~~~ |
|~~|-------|~~  |
|  |-------|    |
|  |-------|~~~ |
+--+-------+----+

This is meant to be used with bigger terminal sizes
embed
Manos Pitsidianakis 2019-09-14 12:43:19 +03:00
parent e3cd2d4c67
commit 3ae2d03663
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
6 changed files with 1412 additions and 9 deletions

View File

@ -21,6 +21,9 @@
use super::*; use super::*;
mod conversations;
pub use self::conversations::*;
mod compact; mod compact;
pub use self::compact::*; pub use self::compact::*;
@ -62,6 +65,7 @@ pub enum ListingComponent {
Plain(PlainListing), Plain(PlainListing),
Threaded(ThreadListing), Threaded(ThreadListing),
Compact(CompactListing), Compact(CompactListing),
Conversations(ConversationsListing),
} }
use crate::ListingComponent::*; use crate::ListingComponent::*;
@ -71,6 +75,7 @@ impl ListingTrait for ListingComponent {
Compact(ref l) => l.coordinates(), Compact(ref l) => l.coordinates(),
Plain(ref l) => l.coordinates(), Plain(ref l) => l.coordinates(),
Threaded(ref l) => l.coordinates(), Threaded(ref l) => l.coordinates(),
Conversations(ref l) => l.coordinates(),
} }
} }
fn set_coordinates(&mut self, c: (usize, usize, Option<EnvelopeHash>)) { fn set_coordinates(&mut self, c: (usize, usize, Option<EnvelopeHash>)) {
@ -78,6 +83,7 @@ impl ListingTrait for ListingComponent {
Compact(ref mut l) => l.set_coordinates(c), Compact(ref mut l) => l.set_coordinates(c),
Plain(ref mut l) => l.set_coordinates(c), Plain(ref mut l) => l.set_coordinates(c),
Threaded(ref mut l) => l.set_coordinates(c), Threaded(ref mut l) => l.set_coordinates(c),
Conversations(ref mut l) => l.set_coordinates(c),
} }
} }
fn draw_list(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) { fn draw_list(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
@ -85,6 +91,7 @@ impl ListingTrait for ListingComponent {
Compact(ref mut l) => l.draw_list(grid, area, context), Compact(ref mut l) => l.draw_list(grid, area, context),
Plain(ref mut l) => l.draw_list(grid, area, context), Plain(ref mut l) => l.draw_list(grid, area, context),
Threaded(ref mut l) => l.draw_list(grid, area, context), Threaded(ref mut l) => l.draw_list(grid, area, context),
Conversations(ref mut l) => l.draw_list(grid, area, context),
} }
} }
fn highlight_line(&mut self, grid: &mut CellBuffer, area: Area, idx: usize, context: &Context) { fn highlight_line(&mut self, grid: &mut CellBuffer, area: Area, idx: usize, context: &Context) {
@ -92,6 +99,7 @@ impl ListingTrait for ListingComponent {
Compact(ref mut l) => l.highlight_line(grid, area, idx, context), Compact(ref mut l) => l.highlight_line(grid, area, idx, context),
Plain(ref mut l) => l.highlight_line(grid, area, idx, context), Plain(ref mut l) => l.highlight_line(grid, area, idx, context),
Threaded(ref mut l) => l.highlight_line(grid, area, idx, context), Threaded(ref mut l) => l.highlight_line(grid, area, idx, context),
Conversations(ref mut l) => l.highlight_line(grid, area, idx, context),
} }
} }
} }
@ -126,6 +134,15 @@ impl ListingComponent {
new_l.set_coordinates((coors.0, coors.1, None)); new_l.set_coordinates((coors.0, coors.1, None));
*self = Compact(new_l); *self = Compact(new_l);
} }
IndexStyle::Conversations => {
if let Conversations(_) = self {
return;
}
let mut new_l = ConversationsListing::default();
let coors = self.coordinates();
new_l.set_coordinates((coors.0, coors.1, None));
*self = Conversations(new_l);
}
} }
} }
} }
@ -151,6 +168,7 @@ impl fmt::Display for Listing {
Compact(ref l) => write!(f, "{}", l), Compact(ref l) => write!(f, "{}", l),
Plain(ref l) => write!(f, "{}", l), Plain(ref l) => write!(f, "{}", l),
Threaded(ref l) => write!(f, "{}", l), Threaded(ref l) => write!(f, "{}", l),
Conversations(ref l) => write!(f, "{}", l),
} }
} }
} }
@ -196,6 +214,7 @@ impl Component for Listing {
Compact(ref mut l) => l.draw(grid, area, context), Compact(ref mut l) => l.draw(grid, area, context),
Plain(ref mut l) => l.draw(grid, area, context), Plain(ref mut l) => l.draw(grid, area, context),
Threaded(ref mut l) => l.draw(grid, area, context), Threaded(ref mut l) => l.draw(grid, area, context),
Conversations(ref mut l) => l.draw(grid, area, context),
} }
} else if right_component_width == 0 { } else if right_component_width == 0 {
self.draw_menu(grid, area, context); self.draw_menu(grid, area, context);
@ -211,6 +230,9 @@ impl Component for Listing {
Threaded(ref mut l) => { Threaded(ref mut l) => {
l.draw(grid, (set_x(upper_left, mid + 1), bottom_right), context) l.draw(grid, (set_x(upper_left, mid + 1), bottom_right), context)
} }
Conversations(ref mut l) => {
l.draw(grid, (set_x(upper_left, mid + 1), bottom_right), context)
}
} }
} }
} }
@ -219,6 +241,7 @@ impl Component for Listing {
Plain(ref mut l) => l.process_event(event, context), Plain(ref mut l) => l.process_event(event, context),
Compact(ref mut l) => l.process_event(event, context), Compact(ref mut l) => l.process_event(event, context),
Threaded(ref mut l) => l.process_event(event, context), Threaded(ref mut l) => l.process_event(event, context),
Conversations(ref mut l) => l.process_event(event, context),
} { } {
return true; return true;
} }
@ -327,6 +350,10 @@ impl Component for Listing {
self.component.set_style(IndexStyle::Compact); self.component.set_style(IndexStyle::Compact);
return true; return true;
} }
Action::Listing(ListingAction::SetConversations) => {
self.component.set_style(IndexStyle::Conversations);
return true;
}
_ => {} _ => {}
}, },
UIEvent::RefreshMailbox((idxa, folder_hash)) => { UIEvent::RefreshMailbox((idxa, folder_hash)) => {
@ -372,6 +399,7 @@ impl Component for Listing {
Compact(ref l) => l.is_dirty(), Compact(ref l) => l.is_dirty(),
Plain(ref l) => l.is_dirty(), Plain(ref l) => l.is_dirty(),
Threaded(ref l) => l.is_dirty(), Threaded(ref l) => l.is_dirty(),
Conversations(ref l) => l.is_dirty(),
} }
} }
fn set_dirty(&mut self) { fn set_dirty(&mut self) {
@ -380,6 +408,7 @@ impl Component for Listing {
Compact(ref mut l) => l.set_dirty(), Compact(ref mut l) => l.set_dirty(),
Plain(ref mut l) => l.set_dirty(), Plain(ref mut l) => l.set_dirty(),
Threaded(ref mut l) => l.set_dirty(), Threaded(ref mut l) => l.set_dirty(),
Conversations(ref mut l) => l.set_dirty(),
} }
} }
@ -388,6 +417,7 @@ impl Component for Listing {
Compact(ref l) => l.get_shortcuts(context), Compact(ref l) => l.get_shortcuts(context),
Plain(ref l) => l.get_shortcuts(context), Plain(ref l) => l.get_shortcuts(context),
Threaded(ref l) => l.get_shortcuts(context), Threaded(ref l) => l.get_shortcuts(context),
Conversations(ref l) => l.get_shortcuts(context),
}; };
let config_map = context.settings.shortcuts.listing.key_values(); let config_map = context.settings.shortcuts.listing.key_values();
map.insert( map.insert(
@ -448,6 +478,7 @@ impl Component for Listing {
Compact(ref l) => l.id(), Compact(ref l) => l.id(),
Plain(ref l) => l.id(), Plain(ref l) => l.id(),
Threaded(ref l) => l.id(), Threaded(ref l) => l.id(),
Conversations(ref l) => l.id(),
} }
} }
fn set_id(&mut self, id: ComponentId) { fn set_id(&mut self, id: ComponentId) {
@ -455,6 +486,7 @@ impl Component for Listing {
Compact(ref mut l) => l.set_id(id), Compact(ref mut l) => l.set_id(id),
Plain(ref mut l) => l.set_id(id), Plain(ref mut l) => l.set_id(id),
Threaded(ref mut l) => l.set_id(id), Threaded(ref mut l) => l.set_id(id),
Conversations(ref mut l) => l.set_id(id),
} }
} }
} }
@ -465,6 +497,7 @@ impl From<IndexStyle> for ListingComponent {
IndexStyle::Plain => Plain(Default::default()), IndexStyle::Plain => Plain(Default::default()),
IndexStyle::Threaded => Threaded(Default::default()), IndexStyle::Threaded => Threaded(Default::default()),
IndexStyle::Compact => Compact(Default::default()), IndexStyle::Compact => Compact(Default::default()),
IndexStyle::Conversations => Conversations(Default::default()),
} }
} }
} }
@ -489,7 +522,7 @@ impl Listing {
}) { }) {
ListingComponent::from(index_style) ListingComponent::from(index_style)
} else { } else {
Compact(Default::default()) Conversations(Default::default())
}; };
Listing { Listing {
component, component,

View File

@ -739,11 +739,9 @@ impl CompactListing {
.duration_since(d) .duration_since(d)
.unwrap_or_else(|_| std::time::Duration::new(std::u64::MAX, 0)); .unwrap_or_else(|_| std::time::Duration::new(std::u64::MAX, 0));
match now.as_secs() { match now.as_secs() {
n if n < 10 * 60 * 60 => format!("{} hours ago{}", n / (60 * 60), " ".repeat(8)), n if n < 10 * 60 * 60 => format!("{} hours ago", n / (60 * 60),),
n if n < 24 * 60 * 60 => format!("{} hours ago{}", n / (60 * 60), " ".repeat(7)), n if n < 24 * 60 * 60 => format!("{} hours ago", n / (60 * 60),),
n if n < 4 * 24 * 60 * 60 => { n if n < 4 * 24 * 60 * 60 => format!("{} days ago", n / (24 * 60 * 60),),
format!("{} days ago{}", n / (24 * 60 * 60), " ".repeat(9))
}
_ => envelope.datetime().format("%Y-%m-%d %H:%M:%S").to_string(), _ => envelope.datetime().format("%Y-%m-%d %H:%M:%S").to_string(),
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -400,6 +400,7 @@ pub enum IndexStyle {
Plain, Plain,
Threaded, Threaded,
Compact, Compact,
Conversations,
} }
impl Default for IndexStyle { impl Default for IndexStyle {
@ -481,7 +482,8 @@ impl<'de> Deserialize<'de> for IndexStyle {
"Plain" | "plain" => Ok(IndexStyle::Plain), "Plain" | "plain" => Ok(IndexStyle::Plain),
"Threaded" | "threaded" => Ok(IndexStyle::Threaded), "Threaded" | "threaded" => Ok(IndexStyle::Threaded),
"Compact" | "compact" => Ok(IndexStyle::Compact), "Compact" | "compact" => Ok(IndexStyle::Compact),
_ => Err(de::Error::custom("invalid `index` value")), "Conversations" | "conversations" => Ok(IndexStyle::Conversations),
_ => Err(de::Error::custom("invalid `index_style` value")),
} }
} }
} }
@ -495,6 +497,7 @@ impl Serialize for IndexStyle {
IndexStyle::Plain => serializer.serialize_str("plain"), IndexStyle::Plain => serializer.serialize_str("plain"),
IndexStyle::Threaded => serializer.serialize_str("threaded"), IndexStyle::Threaded => serializer.serialize_str("threaded"),
IndexStyle::Compact => serializer.serialize_str("compact"), IndexStyle::Compact => serializer.serialize_str("compact"),
IndexStyle::Conversations => serializer.serialize_str("conversations"),
} }
} }
} }

View File

@ -96,11 +96,11 @@ define_commands!([
) )
}, },
{ tags: ["set", "set plain", "set threaded", "set compact"], { tags: ["set", "set plain", "set threaded", "set compact"],
desc: "set [plain/threaded/compact], changes the mail listing view", desc: "set [plain/threaded/compact/conversations], changes the mail listing view",
parser: ( parser: (
named!( named!(
toggle<Action>, toggle<Action>,
preceded!(tag!("set "), alt_complete!(threaded | plain | compact)) preceded!(tag!("set "), alt_complete!(threaded | plain | compact | conversations))
); );
) )
}, },
@ -326,6 +326,12 @@ named!(
compact<Action>, compact<Action>,
map!(ws!(tag!("compact")), |_| Listing(SetCompact)) map!(ws!(tag!("compact")), |_| Listing(SetCompact))
); );
named!(
conversations<Action>,
map!(ws!(tag!("conversations")), |_| Listing(SetConversations))
);
named!( named!(
listing_action<Action>, listing_action<Action>,
alt_complete!(toggle | envelope_action | filter | toggle_thread_snooze) alt_complete!(toggle | envelope_action | filter | toggle_thread_snooze)

View File

@ -37,6 +37,7 @@ pub enum ListingAction {
SetPlain, SetPlain,
SetThreaded, SetThreaded,
SetCompact, SetCompact,
SetConversations,
Filter(String), Filter(String),
SetSeen, SetSeen,
SetUnseen, SetUnseen,