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;
/// 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 {
struct MailboxView {
/// (x, y, z): x is accounts, y is folders, z is index inside a folder.
cursor_pos: (usize, usize, usize),
new_cursor_pos: (usize, usize, usize),
@ -47,28 +45,13 @@ pub struct CompactListing {
movement: Option<PageMovement>,
}
impl ListingTrait for CompactListing {
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 {
impl fmt::Display for MailboxView {
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 */
/* TODO: Make this configurable */
fn make_entry_string(e: &Envelope, len: usize, idx: usize) -> String {
@ -76,7 +59,7 @@ impl CompactListing {
format!(
"{} {} {:.85} ({})",
idx,
&CompactListing::format_date(e),
&MailboxView::format_date(e),
e.subject(),
len
)
@ -84,15 +67,15 @@ impl CompactListing {
format!(
"{} {} {:.85}",
idx,
&CompactListing::format_date(e),
&MailboxView::format_date(e),
e.subject(),
)
}
}
pub fn new() -> Self {
fn new() -> Self {
let content = CellBuffer::new(0, 0, Cell::with_char(' '));
CompactListing {
MailboxView {
cursor_pos: (0, 1, 0),
new_cursor_pos: (0, 0, 0),
length: 0,
@ -114,7 +97,6 @@ impl CompactListing {
if !(self.cursor_pos.0 == self.new_cursor_pos.0
&& self.cursor_pos.1 == self.new_cursor_pos.1)
{
//TODO: store cursor_pos in each folder
self.cursor_pos.2 = 0;
self.new_cursor_pos.2 = 0;
}
@ -209,7 +191,7 @@ impl CompactListing {
Color::Default
};
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,
fg_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) {
if !self.unfocused {
if !self.is_dirty() {
@ -438,47 +420,16 @@ impl Component for CompactListing {
}
UIEventType::Input(Key::Char(k @ 'J')) | UIEventType::Input(Key::Char(k @ 'K')) => {
let folder_length = context.accounts[self.cursor_pos.0].len();
let accounts_length = context.accounts.len();
match k {
'J' if folder_length > 0 => {
if self.new_cursor_pos.1 < folder_length - 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;
'J' if folder_length > 0 && self.new_cursor_pos.1 < folder_length - 1 => {
self.new_cursor_pos.1 = self.cursor_pos.1 + 1;
self.refresh_mailbox(context);
}
'l' if self.cursor_pos.0 > 0 => {
self.new_cursor_pos.0 = self.cursor_pos.0 - 1;
self.new_cursor_pos.1 = 0;
'K' if self.cursor_pos.1 > 0 => {
self.new_cursor_pos.1 = self.cursor_pos.1 - 1;
self.refresh_mailbox(context);
}
_ => {}
_ => return false,
}
return true;
}
@ -637,3 +588,178 @@ impl Component for CompactListing {
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
}
}