ui: hold live entries for each mailbox in CompactListing

embed
Manos Pitsidianakis 2019-04-10 16:51:15 +03:00
parent 0e2e8b09f6
commit 7e80ad2a86
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
1 changed files with 190 additions and 64 deletions

View File

@ -26,10 +26,8 @@ use components::utilities::PageMovement;
const MAX_COLS: usize = 500; const MAX_COLS: usize = 500;
/// A list of all mail (`Envelope`s) in a `Mailbox`. On `\n` it opens the `Envelope` content in a
/// `ThreadView`.
#[derive(Debug)] #[derive(Debug)]
pub struct CompactListing { struct MailboxView {
/// (x, y, z): x is accounts, y is folders, z is index inside a folder. /// (x, y, z): x is accounts, y is folders, z is index inside a folder.
cursor_pos: (usize, usize, usize), cursor_pos: (usize, usize, usize),
new_cursor_pos: (usize, usize, usize), new_cursor_pos: (usize, usize, usize),
@ -47,28 +45,13 @@ pub struct CompactListing {
movement: Option<PageMovement>, movement: Option<PageMovement>,
} }
impl ListingTrait for CompactListing { impl fmt::Display for MailboxView {
fn coordinates(&self) -> (usize, usize, Option<EnvelopeHash>) {
(self.cursor_pos.0, self.cursor_pos.1, None)
}
fn set_coordinates(&mut self, coordinates: (usize, usize, Option<EnvelopeHash>)) {
self.new_cursor_pos = (coordinates.0, coordinates.1, 0);
}
}
impl Default for CompactListing {
fn default() -> Self {
Self::new()
}
}
impl fmt::Display for CompactListing {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "mail") write!(f, "")
} }
} }
impl CompactListing { impl MailboxView {
/// Helper function to format entry strings for CompactListing */ /// Helper function to format entry strings for CompactListing */
/* TODO: Make this configurable */ /* TODO: Make this configurable */
fn make_entry_string(e: &Envelope, len: usize, idx: usize) -> String { fn make_entry_string(e: &Envelope, len: usize, idx: usize) -> String {
@ -76,7 +59,7 @@ impl CompactListing {
format!( format!(
"{} {} {:.85} ({})", "{} {} {:.85} ({})",
idx, idx,
&CompactListing::format_date(e), &MailboxView::format_date(e),
e.subject(), e.subject(),
len len
) )
@ -84,15 +67,15 @@ impl CompactListing {
format!( format!(
"{} {} {:.85}", "{} {} {:.85}",
idx, idx,
&CompactListing::format_date(e), &MailboxView::format_date(e),
e.subject(), e.subject(),
) )
} }
} }
pub fn new() -> Self { fn new() -> Self {
let content = CellBuffer::new(0, 0, Cell::with_char(' ')); let content = CellBuffer::new(0, 0, Cell::with_char(' '));
CompactListing { MailboxView {
cursor_pos: (0, 1, 0), cursor_pos: (0, 1, 0),
new_cursor_pos: (0, 0, 0), new_cursor_pos: (0, 0, 0),
length: 0, length: 0,
@ -114,7 +97,6 @@ impl CompactListing {
if !(self.cursor_pos.0 == self.new_cursor_pos.0 if !(self.cursor_pos.0 == self.new_cursor_pos.0
&& self.cursor_pos.1 == self.new_cursor_pos.1) && self.cursor_pos.1 == self.new_cursor_pos.1)
{ {
//TODO: store cursor_pos in each folder
self.cursor_pos.2 = 0; self.cursor_pos.2 = 0;
self.new_cursor_pos.2 = 0; self.new_cursor_pos.2 = 0;
} }
@ -209,7 +191,7 @@ impl CompactListing {
Color::Default Color::Default
}; };
let (x, _) = write_string_to_grid( let (x, _) = write_string_to_grid(
&CompactListing::make_entry_string(root_envelope, thread_node.len(), idx), &MailboxView::make_entry_string(root_envelope, thread_node.len(), idx),
&mut self.content, &mut self.content,
fg_color, fg_color,
bg_color, bg_color,
@ -377,7 +359,7 @@ impl CompactListing {
} }
} }
impl Component for CompactListing { impl Component for MailboxView {
fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) { fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
if !self.unfocused { if !self.unfocused {
if !self.is_dirty() { if !self.is_dirty() {
@ -438,47 +420,16 @@ impl Component for CompactListing {
} }
UIEventType::Input(Key::Char(k @ 'J')) | UIEventType::Input(Key::Char(k @ 'K')) => { UIEventType::Input(Key::Char(k @ 'J')) | UIEventType::Input(Key::Char(k @ 'K')) => {
let folder_length = context.accounts[self.cursor_pos.0].len(); let folder_length = context.accounts[self.cursor_pos.0].len();
let accounts_length = context.accounts.len();
match k { match k {
'J' if folder_length > 0 => { 'J' if folder_length > 0 && self.new_cursor_pos.1 < folder_length - 1 => {
if self.new_cursor_pos.1 < folder_length - 1 { self.new_cursor_pos.1 = self.cursor_pos.1 + 1;
self.new_cursor_pos.1 = self.cursor_pos.1 + 1;
self.refresh_mailbox(context);
} else if accounts_length > 0 && self.new_cursor_pos.0 < accounts_length - 1
{
self.new_cursor_pos.0 = self.cursor_pos.0 + 1;
self.new_cursor_pos.1 = 0;
self.refresh_mailbox(context);
}
}
'K' => {
if self.cursor_pos.1 > 0 {
self.new_cursor_pos.1 = self.cursor_pos.1 - 1;
self.refresh_mailbox(context);
} else if self.cursor_pos.0 > 0 {
self.new_cursor_pos.0 = self.cursor_pos.0 - 1;
self.new_cursor_pos.1 = 0;
self.refresh_mailbox(context);
}
}
_ => {}
}
return true;
}
UIEventType::Input(Key::Char(k @ 'h')) | UIEventType::Input(Key::Char(k @ 'l')) => {
let accounts_length = context.accounts.len();
match k {
'h' if accounts_length > 0 && self.new_cursor_pos.0 < accounts_length - 1 => {
self.new_cursor_pos.0 = self.cursor_pos.0 + 1;
self.new_cursor_pos.1 = 0;
self.refresh_mailbox(context); self.refresh_mailbox(context);
} }
'l' if self.cursor_pos.0 > 0 => { 'K' if self.cursor_pos.1 > 0 => {
self.new_cursor_pos.0 = self.cursor_pos.0 - 1; self.new_cursor_pos.1 = self.cursor_pos.1 - 1;
self.new_cursor_pos.1 = 0;
self.refresh_mailbox(context); self.refresh_mailbox(context);
} }
_ => {} _ => return false,
} }
return true; return true;
} }
@ -637,3 +588,178 @@ impl Component for CompactListing {
map map
} }
} }
/// A list of all mail (`Envelope`s) in a `Mailbox`. On `\n` it opens the `Envelope` content in a
/// `ThreadView`.
#[derive(Debug)]
pub struct CompactListing {
views: Vec<MailboxView>,
cursor: usize,
dirty: bool,
populated: bool,
}
impl ListingTrait for CompactListing {
fn coordinates(&self) -> (usize, usize, Option<EnvelopeHash>) {
(self.cursor, self.views[self.cursor].cursor_pos.1, None)
}
fn set_coordinates(&mut self, coordinates: (usize, usize, Option<EnvelopeHash>)) {
self.views[self.cursor].new_cursor_pos = (coordinates.0, coordinates.1, 0);
}
}
impl fmt::Display for CompactListing {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "mail")
}
}
impl Default for CompactListing {
fn default() -> Self {
CompactListing::new()
}
}
impl CompactListing {
pub fn new() -> Self {
CompactListing {
views: Vec::with_capacity(8),
cursor: 0,
dirty: true,
populated: false,
}
}
}
impl Component for CompactListing {
fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
if !self.populated {
eprintln!("populating");
for (idx, a) in context.accounts.iter().enumerate() {
for (fidx, _) in a.iter_mailboxes().enumerate() {
let mut m = MailboxView::new();
m.new_cursor_pos = (idx, fidx, 0);
self.views.push(m);
}
}
self.populated = true;
}
if self.views.is_empty() {
return;
}
self.views[self.cursor].draw(grid, area, context);
}
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
if self.views.is_empty() {
return false;
}
match event.event_type {
UIEventType::Input(Key::Char(k @ 'J')) | UIEventType::Input(Key::Char(k @ 'K')) => {
let folder_length = context.accounts[self.views[self.cursor].cursor_pos.0].len();
match k {
'J' if folder_length > 0 => {
if self.cursor < self.views.len() - 1 {
self.cursor += 1;
self.dirty = true;
}
}
'K' if self.cursor > 0 => {
self.cursor -= 1;
self.dirty = true;
}
_ => return false,
}
self.views[self.cursor].refresh_mailbox(context);
return true;
}
UIEventType::Input(Key::Char(k @ 'h')) | UIEventType::Input(Key::Char(k @ 'l')) => {
let binary_search_account = |entries: &[MailboxView], x: usize| -> Option<usize> {
if entries.is_empty() {
return None;
}
let mut low = 0;
let mut high = entries.len() - 1;
while low < high {
let mid = low + (high - low) / 2;
if x > entries[mid].new_cursor_pos.0 {
low = mid + 1;
} else {
high = mid;
}
}
return Some(low);
};
match k {
'h' => {
if let Some(next) = binary_search_account(
&self.views.as_slice()[self.cursor..],
self.views[self.cursor].new_cursor_pos.0 + 1,
) {
self.cursor += next;
self.dirty = true;
}
}
'l' if self.views[self.cursor].cursor_pos.0 > 0 => {
if let Some(next) = binary_search_account(
&self.views.as_slice()[..self.cursor],
self.views[self.cursor].new_cursor_pos.0 - 1,
) {
self.cursor = next;
self.dirty = true;
}
}
_ => return false,
}
self.views[self.cursor].refresh_mailbox(context);
return true;
}
_ => {
return self.views[self.cursor].process_event(event, context);
}
}
}
fn is_dirty(&self) -> bool {
if self.views.is_empty() {
return self.dirty;
}
self.dirty || self.views[self.cursor].is_dirty()
}
fn set_dirty(&mut self) {
if self.views.is_empty() {
return;
}
self.views[self.cursor].set_dirty();
self.dirty = true;
}
fn get_shortcuts(&self, context: &Context) -> ShortcutMap {
if self.views.is_empty() {
return Default::default();
}
let mut map = self.views[self.cursor].get_shortcuts(context);
let config_map = context.settings.shortcuts.compact_listing.key_values();
map.insert(
"prev_account",
if let Some(key) = config_map.get("prev_account") {
(*key).clone()
} else {
Key::Char('h')
},
);
map.insert(
"next_account",
if let Some(key) = config_map.get("next_account") {
(*key).clone()
} else {
Key::Char('l')
},
);
map
}
}