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 sizesembed
parent
e3cd2d4c67
commit
3ae2d03663
|
@ -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,
|
||||||
|
|
|
@ -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
|
@ -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"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -37,6 +37,7 @@ pub enum ListingAction {
|
||||||
SetPlain,
|
SetPlain,
|
||||||
SetThreaded,
|
SetThreaded,
|
||||||
SetCompact,
|
SetCompact,
|
||||||
|
SetConversations,
|
||||||
Filter(String),
|
Filter(String),
|
||||||
SetSeen,
|
SetSeen,
|
||||||
SetUnseen,
|
SetUnseen,
|
||||||
|
|
Loading…
Reference in New Issue