From cbaf21764c033799b5cd3e830e9fd32085f55625 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Mon, 9 Nov 2020 19:32:38 +0200 Subject: [PATCH] Remove status tab, move account status page to listing --- src/bin.rs | 4 - src/components/mail/listing.rs | 557 ++++++++++++++++++--------------- src/components/mail/status.rs | 330 ++----------------- 3 files changed, 331 insertions(+), 560 deletions(-) diff --git a/src/bin.rs b/src/bin.rs index bb22acb0..586e94b8 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -350,10 +350,6 @@ fn run_app(opt: Opt) -> Result<()> { vec![ Box::new(listing::Listing::new(&mut state.context)), Box::new(ContactList::new(&state.context)), - Box::new(StatusPanel::new(crate::conf::value( - &state.context, - "theme_default", - ))), ], &state.context, )); diff --git a/src/components/mail/listing.rs b/src/components/mail/listing.rs index 15d12223..cebe022e 100644 --- a/src/components/mail/listing.rs +++ b/src/components/mail/listing.rs @@ -472,6 +472,7 @@ enum ListingFocus { pub struct Listing { component: ListingComponent, accounts: Vec, + status: Option, dirty: bool, visible: bool, cursor_pos: (usize, usize), @@ -570,7 +571,11 @@ impl Component for Listing { } } - self.component.draw(grid, area, context); + if let Some(s) = self.status.as_mut() { + s.draw(grid, area, context); + } else { + self.component.draw(grid, area, context); + } } else if right_component_width == 0 { self.draw_menu(grid, area, context); } else { @@ -583,8 +588,12 @@ impl Component for Listing { } } } - self.component - .draw(grid, (set_x(upper_left, mid + 1), bottom_right), context); + if let Some(s) = self.status.as_mut() { + s.draw(grid, (set_x(upper_left, mid + 1), bottom_right), context); + } else { + self.component + .draw(grid, (set_x(upper_left, mid + 1), bottom_right), context); + } } self.dirty = false; } @@ -672,7 +681,17 @@ impl Component for Listing { _ => {} } - if self.focus == ListingFocus::Mailbox && self.component.process_event(event, context) { + if self.focus == ListingFocus::Mailbox && self.status.is_some() { + if let Some(s) = self.status.as_mut() { + if s.process_event(event, context) { + return true; + } + } + } + if self.focus == ListingFocus::Mailbox + && self.status.is_none() + && self.component.process_event(event, context) + { return true; } @@ -817,188 +836,6 @@ impl Component for Listing { return true; } - UIEvent::Action(ref action) => match action { - Action::Listing(ListingAction::SetPlain) => { - self.component.set_style(IndexStyle::Plain); - return true; - } - Action::Listing(ListingAction::SetThreaded) => { - self.component.set_style(IndexStyle::Threaded); - return true; - } - Action::Listing(ListingAction::SetCompact) => { - self.component.set_style(IndexStyle::Compact); - return true; - } - Action::Listing(ListingAction::SetConversations) => { - self.component.set_style(IndexStyle::Conversations); - return true; - } - Action::Listing(ListingAction::Import(file_path, mailbox_path)) => { - let account = &mut context.accounts[self.cursor_pos.0]; - if let Err(err) = account - .mailbox_by_path(&mailbox_path) - .and_then(|mailbox_hash| { - Ok(( - std::fs::read(&file_path).chain_err_summary(|| { - format!("Could not read {}", file_path.display()) - })?, - mailbox_hash, - )) - }) - .and_then(|(bytes, mailbox_hash)| { - account.save(&bytes, mailbox_hash, None) - }) - { - context.replies.push_back(UIEvent::StatusEvent( - StatusEvent::DisplayMessage(err.to_string()), - )); - } - return true; - } - Action::Listing(a @ ListingAction::SetSeen) - | Action::Listing(a @ ListingAction::SetUnseen) - | Action::Listing(a @ ListingAction::Delete) - | Action::Listing(a @ ListingAction::CopyTo(_)) - | Action::Listing(a @ ListingAction::MoveTo(_)) - | Action::Listing(a @ ListingAction::CopyToOtherAccount(_, _)) - | Action::Listing(a @ ListingAction::MoveToOtherAccount(_, _)) - | Action::Listing(a @ ListingAction::Tag(_)) => { - let focused = self.component.get_focused_items(context); - self.component.perform_action(context, focused, a); - let mut row_updates: SmallVec<[ThreadHash; 8]> = SmallVec::new(); - for (k, v) in self.component.selection().iter_mut() { - if *v { - *v = false; - row_updates.push(*k); - } - } - self.component.row_updates().extend(row_updates.drain(..)); - self.component.set_dirty(true); - return true; - } - Action::ViewMailbox(idx) => { - if let Some((_, _, _, mailbox_hash)) = - self.accounts[self.cursor_pos.0].entries.get(*idx) - { - let account_hash = self.accounts[self.cursor_pos.0].hash; - self.cursor_pos.1 = *idx; - self.component - .set_coordinates((account_hash, *mailbox_hash)); - self.set_dirty(true); - } else { - return true; - } - return true; - } - _ => {} - }, - UIEvent::ChangeMode(UIMode::Normal) => { - self.dirty = true; - } - UIEvent::Resize => { - self.set_dirty(true); - } - UIEvent::Input(ref key) - if shortcut!(key == shortcuts[Listing::DESCRIPTION]["scroll_up"]) => - { - let amount = if self.cmd_buf.is_empty() { - 1 - } else if let Ok(amount) = self.cmd_buf.parse::() { - self.cmd_buf.clear(); - self.component.set_modifier_active(false); - context - .replies - .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); - amount - } else { - self.cmd_buf.clear(); - self.component.set_modifier_active(false); - context - .replies - .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); - return true; - }; - self.component.set_movement(PageMovement::Up(amount)); - return true; - } - UIEvent::Input(ref key) - if shortcut!(key == shortcuts[Listing::DESCRIPTION]["scroll_down"]) => - { - let amount = if self.cmd_buf.is_empty() { - 1 - } else if let Ok(amount) = self.cmd_buf.parse::() { - self.cmd_buf.clear(); - self.component.set_modifier_active(false); - context - .replies - .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); - amount - } else { - self.cmd_buf.clear(); - self.component.set_modifier_active(false); - context - .replies - .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); - return true; - }; - self.component.set_movement(PageMovement::Down(amount)); - return true; - } - UIEvent::Input(ref key) - if shortcut!(key == shortcuts[Listing::DESCRIPTION]["prev_page"]) => - { - let mult = if self.cmd_buf.is_empty() { - 1 - } else if let Ok(mult) = self.cmd_buf.parse::() { - self.cmd_buf.clear(); - self.component.set_modifier_active(false); - context - .replies - .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); - mult - } else { - self.cmd_buf.clear(); - self.component.set_modifier_active(false); - context - .replies - .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); - return true; - }; - self.component.set_movement(PageMovement::PageUp(mult)); - return true; - } - UIEvent::Input(ref key) - if shortcut!(key == shortcuts[Listing::DESCRIPTION]["next_page"]) => - { - let mult = if self.cmd_buf.is_empty() { - 1 - } else if let Ok(mult) = self.cmd_buf.parse::() { - self.cmd_buf.clear(); - self.component.set_modifier_active(false); - context - .replies - .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); - mult - } else { - self.cmd_buf.clear(); - self.component.set_modifier_active(false); - context - .replies - .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); - return true; - }; - self.component.set_movement(PageMovement::PageDown(mult)); - return true; - } - UIEvent::Input(ref key) if *key == Key::Home => { - self.component.set_movement(PageMovement::Home); - return true; - } - UIEvent::Input(ref key) if *key == Key::End => { - self.component.set_movement(PageMovement::End); - return true; - } UIEvent::Input(ref k) if shortcut!( k == shortcuts[Listing::DESCRIPTION]["toggle_menu_visibility"] @@ -1007,67 +844,256 @@ impl Component for Listing { self.menu_visibility = !self.menu_visibility; self.set_dirty(true); } - UIEvent::Input(ref key) - if shortcut!(key == shortcuts[Listing::DESCRIPTION]["search"]) => - { - context - .replies - .push_back(UIEvent::CmdInput(Key::Paste("search ".to_string()))); - context - .replies - .push_back(UIEvent::ChangeMode(UIMode::Command)); - return true; + UIEvent::ChangeMode(UIMode::Normal) => { + self.dirty = true; } - UIEvent::Input(ref key) - if shortcut!(key == shortcuts[Listing::DESCRIPTION]["set_seen"]) => - { - let mut event = UIEvent::Action(Action::Listing(ListingAction::SetSeen)); - if self.process_event(&mut event, context) { - return true; - } + UIEvent::Resize => { + self.set_dirty(true); } - UIEvent::Input(ref key) - if shortcut!(key == shortcuts[Listing::DESCRIPTION]["refresh"]) => - { - let account = &mut context.accounts[self.cursor_pos.0]; - if let Some(&mailbox_hash) = account.mailboxes_order.get(self.cursor_pos.1) { - if let Err(err) = account.refresh(mailbox_hash) { - context.replies.push_back(UIEvent::Notification( - Some("Could not refresh.".to_string()), - err.to_string(), - Some(NotificationType::Error(err.kind)), - )); - } + UIEvent::Action(Action::ViewMailbox(ref idx)) => { + if let Some((_, _, _, mailbox_hash)) = + self.accounts[self.cursor_pos.0].entries.get(*idx) + { + let account_hash = self.accounts[self.cursor_pos.0].hash; + self.cursor_pos.1 = *idx; + self.status = None; + self.component + .set_coordinates((account_hash, *mailbox_hash)); + self.set_dirty(true); } return true; } - UIEvent::Input(ref key) - if !self.component.unfocused() - && shortcut!(key == shortcuts[Listing::DESCRIPTION]["union_modifier"]) - && self.component.modifier_command().is_some() => - { - self.component.set_modifier_command(Some(Modifier::Union)); - } - UIEvent::Input(ref key) - if !self.component.unfocused() - && shortcut!(key == shortcuts[Listing::DESCRIPTION]["diff_modifier"]) - && self.component.modifier_command().is_some() => - { - self.component - .set_modifier_command(Some(Modifier::Difference)); - } - UIEvent::Input(ref key) - if !self.component.unfocused() - && shortcut!( - key == shortcuts[Listing::DESCRIPTION]["intersection_modifier"] - ) - && self.component.modifier_command().is_some() => - { - self.component - .set_modifier_command(Some(Modifier::Intersection)); - } _ => {} } + + if self.status.is_none() { + match event { + UIEvent::Action(ref action) => match action { + Action::Listing(ListingAction::SetPlain) => { + self.component.set_style(IndexStyle::Plain); + return true; + } + Action::Listing(ListingAction::SetThreaded) => { + self.component.set_style(IndexStyle::Threaded); + return true; + } + Action::Listing(ListingAction::SetCompact) => { + self.component.set_style(IndexStyle::Compact); + return true; + } + Action::Listing(ListingAction::SetConversations) => { + self.component.set_style(IndexStyle::Conversations); + return true; + } + Action::Listing(ListingAction::Import(file_path, mailbox_path)) => { + let account = &mut context.accounts[self.cursor_pos.0]; + if let Err(err) = account + .mailbox_by_path(&mailbox_path) + .and_then(|mailbox_hash| { + Ok(( + std::fs::read(&file_path).chain_err_summary(|| { + format!("Could not read {}", file_path.display()) + })?, + mailbox_hash, + )) + }) + .and_then(|(bytes, mailbox_hash)| { + account.save(&bytes, mailbox_hash, None) + }) + { + context.replies.push_back(UIEvent::StatusEvent( + StatusEvent::DisplayMessage(err.to_string()), + )); + } + return true; + } + Action::Listing(a @ ListingAction::SetSeen) + | Action::Listing(a @ ListingAction::SetUnseen) + | Action::Listing(a @ ListingAction::Delete) + | Action::Listing(a @ ListingAction::CopyTo(_)) + | Action::Listing(a @ ListingAction::MoveTo(_)) + | Action::Listing(a @ ListingAction::CopyToOtherAccount(_, _)) + | Action::Listing(a @ ListingAction::MoveToOtherAccount(_, _)) + | Action::Listing(a @ ListingAction::Tag(_)) => { + let focused = self.component.get_focused_items(context); + self.component.perform_action(context, focused, a); + let mut row_updates: SmallVec<[ThreadHash; 8]> = SmallVec::new(); + for (k, v) in self.component.selection().iter_mut() { + if *v { + *v = false; + row_updates.push(*k); + } + } + } + _ => {} + }, + UIEvent::Input(ref key) + if shortcut!(key == shortcuts[Listing::DESCRIPTION]["scroll_up"]) => + { + let amount = if self.cmd_buf.is_empty() { + 1 + } else if let Ok(amount) = self.cmd_buf.parse::() { + self.cmd_buf.clear(); + self.component.set_modifier_active(false); + context + .replies + .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); + amount + } else { + self.cmd_buf.clear(); + self.component.set_modifier_active(false); + context + .replies + .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); + return true; + }; + self.component.set_movement(PageMovement::Up(amount)); + return true; + } + UIEvent::Input(ref key) + if shortcut!(key == shortcuts[Listing::DESCRIPTION]["scroll_down"]) => + { + let amount = if self.cmd_buf.is_empty() { + 1 + } else if let Ok(amount) = self.cmd_buf.parse::() { + self.cmd_buf.clear(); + self.component.set_modifier_active(false); + context + .replies + .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); + amount + } else { + self.cmd_buf.clear(); + self.component.set_modifier_active(false); + context + .replies + .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); + return true; + }; + self.component.set_movement(PageMovement::Down(amount)); + return true; + } + UIEvent::Input(ref key) + if shortcut!(key == shortcuts[Listing::DESCRIPTION]["prev_page"]) => + { + let mult = if self.cmd_buf.is_empty() { + 1 + } else if let Ok(mult) = self.cmd_buf.parse::() { + self.cmd_buf.clear(); + self.component.set_modifier_active(false); + context + .replies + .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); + mult + } else { + self.cmd_buf.clear(); + self.component.set_modifier_active(false); + context + .replies + .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); + return true; + }; + self.component.set_movement(PageMovement::PageUp(mult)); + return true; + } + UIEvent::Input(ref key) + if shortcut!(key == shortcuts[Listing::DESCRIPTION]["next_page"]) => + { + let mult = if self.cmd_buf.is_empty() { + 1 + } else if let Ok(mult) = self.cmd_buf.parse::() { + self.cmd_buf.clear(); + self.component.set_modifier_active(false); + context + .replies + .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); + mult + } else { + self.cmd_buf.clear(); + self.component.set_modifier_active(false); + context + .replies + .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); + return true; + }; + self.component.set_movement(PageMovement::PageDown(mult)); + return true; + } + UIEvent::Input(ref key) if *key == Key::Home => { + self.component.set_movement(PageMovement::Home); + return true; + } + UIEvent::Input(ref key) if *key == Key::End => { + self.component.set_movement(PageMovement::End); + return true; + } + UIEvent::Input(ref key) + if shortcut!(key == shortcuts[Listing::DESCRIPTION]["search"]) => + { + context + .replies + .push_back(UIEvent::CmdInput(Key::Paste("search ".to_string()))); + context + .replies + .push_back(UIEvent::ChangeMode(UIMode::Command)); + return true; + } + UIEvent::Input(ref key) + if shortcut!(key == shortcuts[Listing::DESCRIPTION]["set_seen"]) => + { + let mut event = UIEvent::Action(Action::Listing(ListingAction::SetSeen)); + if self.process_event(&mut event, context) { + return true; + } + } + UIEvent::Input(ref key) + if shortcut!(key == shortcuts[Listing::DESCRIPTION]["refresh"]) => + { + let account = &mut context.accounts[self.cursor_pos.0]; + if let Some(&mailbox_hash) = account.mailboxes_order.get(self.cursor_pos.1) + { + if let Err(err) = account.refresh(mailbox_hash) { + context.replies.push_back(UIEvent::Notification( + Some("Could not refresh.".to_string()), + err.to_string(), + Some(NotificationType::Error(err.kind)), + )); + } + } + return true; + } + UIEvent::Input(ref key) + if !self.component.unfocused() + && shortcut!( + key == shortcuts[Listing::DESCRIPTION]["union_modifier"] + ) + && self.component.modifier_command().is_some() => + { + self.component.set_modifier_command(Some(Modifier::Union)); + } + UIEvent::Input(ref key) + if !self.component.unfocused() + && shortcut!( + key == shortcuts[Listing::DESCRIPTION]["diff_modifier"] + ) + && self.component.modifier_command().is_some() => + { + self.component + .set_modifier_command(Some(Modifier::Difference)); + } + UIEvent::Input(ref key) + if !self.component.unfocused() + && shortcut!( + key == shortcuts[Listing::DESCRIPTION]["intersection_modifier"] + ) + && self.component.modifier_command().is_some() => + { + self.component + .set_modifier_command(Some(Modifier::Intersection)); + } + _ => {} + } + } } else if self.focus == ListingFocus::Menu { match *event { UIEvent::Input(Key::Right) => { @@ -1076,10 +1102,24 @@ impl Component for Listing { self.set_dirty(true); return true; } + UIEvent::Input(ref k) + if shortcut!(k == shortcuts[Listing::DESCRIPTION]["open_mailbox"]) + && self.menu_cursor_pos.1 == 0 => + { + self.status = Some(AccountStatus::new( + self.menu_cursor_pos.0, + self.theme_default, + )); + self.focus = ListingFocus::Mailbox; + self.ratio = 90; + return true; + } UIEvent::Input(ref k) if shortcut!(k == shortcuts[Listing::DESCRIPTION]["open_mailbox"]) => { self.cursor_pos = self.menu_cursor_pos; + self.cursor_pos.1 = self.cursor_pos.1.saturating_sub(1); + self.status = None; self.change_account(context); self.focus = ListingFocus::Mailbox; self.ratio = 90; @@ -1118,10 +1158,8 @@ impl Component for Listing { self.menu_cursor_pos.1 -= 1; } else if self.menu_cursor_pos.0 > 0 { self.menu_cursor_pos.0 -= 1; - self.menu_cursor_pos.1 = self.accounts[self.menu_cursor_pos.0] - .entries - .len() - .saturating_sub(1); + self.menu_cursor_pos.1 = + self.accounts[self.menu_cursor_pos.0].entries.len(); } else { return true; } @@ -1129,7 +1167,7 @@ impl Component for Listing { } } else if shortcut!(k == shortcuts[Listing::DESCRIPTION]["scroll_down"]) { while amount > 0 { - if self.menu_cursor_pos.1 + 1 + if self.menu_cursor_pos.1 < self.accounts[self.menu_cursor_pos.0].entries.len() { self.menu_cursor_pos.1 += 1; @@ -1170,7 +1208,7 @@ impl Component for Listing { k if shortcut!(k == shortcuts[Listing::DESCRIPTION]["next_mailbox"]) => { if self.accounts[self.menu_cursor_pos.0] .entries - .get(self.menu_cursor_pos.1 + amount) + .get(self.menu_cursor_pos.1.saturating_sub(1) + amount) .is_some() { self.menu_cursor_pos.1 += amount; @@ -1180,10 +1218,10 @@ impl Component for Listing { } } k if shortcut!(k == shortcuts[Listing::DESCRIPTION]["prev_mailbox"]) => { - if self.cursor_pos.1 >= amount { + if self.cursor_pos.1 >= amount + 1 { if self.accounts[self.menu_cursor_pos.0] .entries - .get(self.menu_cursor_pos.1 - amount) + .get(self.menu_cursor_pos.1.saturating_sub(1) - amount) .is_some() { self.menu_cursor_pos.1 -= amount; @@ -1305,11 +1343,20 @@ impl Component for Listing { false } fn is_dirty(&self) -> bool { - self.dirty || self.component.is_dirty() + self.dirty + || self + .status + .as_ref() + .map(Component::is_dirty) + .unwrap_or_else(|| self.component.is_dirty()) } fn set_dirty(&mut self, value: bool) { self.dirty = value; - self.component.set_dirty(value); + if let Some(s) = self.status.as_mut() { + s.set_dirty(value); + } else { + self.component.set_dirty(value); + } } fn get_shortcuts(&self, context: &Context) -> ShortcutMaps { @@ -1387,6 +1434,7 @@ impl Listing { let mut ret = Listing { component: Offline(OfflineListing::new((account_entries[0].hash, 0))), accounts: account_entries, + status: None, visible: true, dirty: true, cursor_pos: (0, 0), @@ -1481,7 +1529,11 @@ impl Listing { } let account_attrs = if must_highlight_account { - crate::conf::value(context, "mail.sidebar_highlighted_account_name") + if self.focus == ListingFocus::Menu && self.menu_cursor_pos.1 == 0 { + crate::conf::value(context, "mail.sidebar_highlighted") + } else { + crate::conf::value(context, "mail.sidebar_highlighted_account_name") + } } else { crate::conf::value(context, "mail.sidebar_account_name") }; @@ -1519,7 +1571,7 @@ impl Listing { } let (att, index_att, unread_count_att) = if must_highlight_account { if (self.focus == ListingFocus::Mailbox && self.cursor_pos.1 == idx) - || (self.focus == ListingFocus::Menu && self.menu_cursor_pos.1 == idx) + || (self.focus == ListingFocus::Menu && self.menu_cursor_pos.1 == idx + 1) { let mut ret = ( crate::conf::value(context, "mail.sidebar_highlighted"), @@ -1724,5 +1776,6 @@ impl Listing { self.get_status(context), ))); self.menu_cursor_pos = self.cursor_pos; + self.menu_cursor_pos.1 += 1; } } diff --git a/src/components/mail/status.rs b/src/components/mail/status.rs index 413bab9b..222dca54 100644 --- a/src/components/mail/status.rs +++ b/src/components/mail/status.rs @@ -21,299 +21,6 @@ use super::*; -#[derive(Debug)] -pub struct StatusPanel { - cursor: (usize, usize), - account_cursor: usize, - status: Option, - content: CellBuffer, - dirty: bool, - theme_default: ThemeAttribute, - id: ComponentId, -} - -impl core::fmt::Display for StatusPanel { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "status") - } -} - -impl Component for StatusPanel { - fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) { - if let Some(ref mut status) = self.status { - status.draw(grid, area, context); - return; - } - self.draw_accounts(context); - let (width, height) = self.content.size(); - let (cols, rows) = (width!(area), height!(area)); - self.cursor = ( - std::cmp::min(width.saturating_sub(cols), self.cursor.0), - std::cmp::min(height.saturating_sub(rows), self.cursor.1), - ); - clear_area(grid, area, self.theme_default); - copy_area( - grid, - &self.content, - area, - ( - ( - std::cmp::min((width - 1).saturating_sub(cols), self.cursor.0), - std::cmp::min((height - 1).saturating_sub(rows), self.cursor.1), - ), - ( - std::cmp::min(self.cursor.0 + cols, width - 1), - std::cmp::min(self.cursor.1 + rows, height - 1), - ), - ), - ); - context.dirty_areas.push_back(area); - } - fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool { - if let Some(ref mut status) = self.status { - if status.process_event(event, context) { - return true; - } - } - - match *event { - UIEvent::Input(Key::Char('k')) if self.status.is_none() => { - self.account_cursor = self.account_cursor.saturating_sub(1); - self.dirty = true; - return true; - } - UIEvent::Input(Key::Char('j')) if self.status.is_none() => { - if self.account_cursor + 1 < context.accounts.len() { - self.account_cursor += 1; - self.dirty = true; - } - return true; - } - UIEvent::Input(Key::Char('\n')) if self.status.is_none() => { - self.status = Some(AccountStatus::new(self.account_cursor, self.theme_default)); - return true; - } - UIEvent::Input(Key::Esc) if self.status.is_some() => { - self.status = None; - return true; - } - UIEvent::Input(Key::Left) if self.status.is_none() => { - self.cursor.0 = self.cursor.0.saturating_sub(1); - self.dirty = true; - return true; - } - UIEvent::Input(Key::Right) if self.status.is_none() => { - self.cursor.0 = self.cursor.0 + 1; - self.dirty = true; - return true; - } - UIEvent::Input(Key::Up) if self.status.is_none() => { - self.cursor.1 = self.cursor.1.saturating_sub(1); - self.dirty = true; - return true; - } - UIEvent::Input(Key::Down) if self.status.is_none() => { - self.cursor.1 = self.cursor.1 + 1; - self.dirty = true; - return true; - } - UIEvent::MailboxUpdate(_) - | UIEvent::StatusEvent(StatusEvent::NewJob(_)) - | UIEvent::StatusEvent(StatusEvent::JobFinished(_)) - | UIEvent::StatusEvent(StatusEvent::JobCanceled(_)) => { - self.set_dirty(true); - } - _ => {} - } - - false - } - fn is_dirty(&self) -> bool { - self.dirty || self.status.as_ref().map(|s| s.is_dirty()).unwrap_or(false) - } - fn set_dirty(&mut self, value: bool) { - self.dirty = value; - if let Some(ref mut status) = self.status { - status.set_dirty(value); - } - } - - fn id(&self) -> ComponentId { - self.id - } - fn set_id(&mut self, id: ComponentId) { - self.id = id; - } -} - -impl StatusPanel { - pub fn new(theme_default: ThemeAttribute) -> StatusPanel { - let default_cell = { - let mut ret = Cell::with_char(' '); - ret.set_fg(theme_default.fg) - .set_bg(theme_default.bg) - .set_attrs(theme_default.attrs); - ret - }; - let mut content = CellBuffer::new(120, 40, default_cell); - content.set_growable(true); - - StatusPanel { - cursor: (0, 0), - account_cursor: 0, - content, - status: None, - dirty: true, - theme_default, - id: ComponentId::new_v4(), - } - } - fn draw_accounts(&mut self, context: &Context) { - let default_cell = { - let mut ret = Cell::with_char(' '); - ret.set_fg(self.theme_default.fg) - .set_bg(self.theme_default.bg) - .set_attrs(self.theme_default.attrs); - ret - }; - self.content - .resize(120, 40 + context.accounts.len() * 45, default_cell); - write_string_to_grid( - "Accounts", - &mut self.content, - self.theme_default.fg, - self.theme_default.bg, - self.theme_default.attrs, - ((2, 2), (120 - 1, 2)), - Some(2), - ); - - for (i, (_h, a)) in context.accounts.iter().enumerate() { - for x in 2..(120 - 1) { - set_and_join_box(&mut self.content, (x, 4 + i * 10), BoxBoundary::Horizontal); - } - //create_box(&mut self.content, ((2, 5 + i * 10), (120 - 1, 15 + i * 10))); - let (x, y) = write_string_to_grid( - a.name(), - &mut self.content, - self.theme_default.fg, - self.theme_default.bg, - Attr::BOLD, - ((3, 4 + i * 10), (120 - 2, 4 + i * 10)), - Some(3), - ); - write_string_to_grid( - " ▒██▒ ", - &mut self.content, - Color::Byte(32), - self.theme_default.bg, - self.theme_default.attrs, - ((x, y), (120 - 2, y)), - None, - ); - write_string_to_grid( - &a.settings.account().identity, - &mut self.content, - self.theme_default.fg, - self.theme_default.bg, - self.theme_default.attrs, - ((4, y + 2), (120 - 2, y + 2)), - None, - ); - if i == self.account_cursor { - for h in 1..8 { - self.content[(2, h + y + 1)].set_ch('*'); - } - } else { - for h in 1..8 { - self.content[(2, h + y + 1)].set_ch(' '); - } - } - let count = a - .mailbox_entries - .values() - .map(|entry| &entry.ref_mailbox) - .fold((0, 0), |acc, f| { - let count = f.count().unwrap_or((0, 0)); - (acc.0 + count.0, acc.1 + count.1) - }); - let (mut column_width, _) = write_string_to_grid( - &format!("Messages total {}, unseen {}", count.1, count.0), - &mut self.content, - self.theme_default.fg, - self.theme_default.bg, - self.theme_default.attrs, - ((5, y + 3), (120 - 2, y + 3)), - None, - ); - column_width = std::cmp::max( - column_width, - write_string_to_grid( - &format!("Contacts total {}", a.address_book.len()), - &mut self.content, - self.theme_default.fg, - self.theme_default.bg, - self.theme_default.attrs, - ((5, y + 4), (120 - 2, y + 4)), - None, - ) - .0, - ); - column_width = std::cmp::max( - column_width, - write_string_to_grid( - &format!("Backend {}", a.settings.account().format()), - &mut self.content, - self.theme_default.fg, - self.theme_default.bg, - self.theme_default.attrs, - ((5, y + 5), (120 - 2, y + 5)), - None, - ) - .0, - ); - if let Err(err) = a.is_online.as_ref() { - write_string_to_grid( - &err.to_string(), - &mut self.content, - self.theme_default.fg, - self.theme_default.bg, - self.theme_default.attrs, - ((5, y + 6), (5 + column_width, y + 6)), - Some(5), - ); - } - /* next column */ - write_string_to_grid( - "Special Mailboxes:", - &mut self.content, - self.theme_default.fg, - self.theme_default.bg, - Attr::BOLD, - ((5 + column_width, y + 2), (120 - 2, y + 2)), - None, - ); - for (i, f) in a - .mailbox_entries - .values() - .map(|entry| &entry.ref_mailbox) - .filter(|f| f.special_usage() != SpecialUsageMailbox::Normal) - .enumerate() - { - write_string_to_grid( - &format!("{}: {}", f.special_usage(), f.path()), - &mut self.content, - self.theme_default.fg, - self.theme_default.bg, - self.theme_default.attrs, - ((5 + column_width, y + 3 + i), (120 - 2, y + 2)), - None, - ); - } - } - } -} - #[derive(Debug)] pub struct AccountStatus { cursor: (usize, usize), @@ -359,17 +66,26 @@ impl Component for AccountStatus { return; } self.dirty = false; - let (mut width, height) = self.content.size(); + let (mut width, _) = self.content.size(); let a = &context.accounts[self.account_pos]; let (_x, _y) = write_string_to_grid( - "(Press Esc to return)", + "Account ", &mut self.content, self.theme_default.fg, self.theme_default.bg, - Attr::BOLD, + self.theme_default.attrs | Attr::UNDERLINE, ((1, 0), (width - 1, 0)), None, ); + let (_x, _y) = write_string_to_grid( + a.name(), + &mut self.content, + self.theme_default.fg, + self.theme_default.bg, + Attr::BOLD | Attr::UNDERLINE, + ((_x, _y), (width - 1, _y)), + None, + ); width = self.content.size().0; let mut line = 2; @@ -447,7 +163,6 @@ impl Component for AccountStatus { ((1, line), (width - 1, line)), None, ); - width = self.content.size().0; for f in a .mailbox_entries .values() @@ -477,7 +192,6 @@ impl Component for AccountStatus { ((1, line), (width - 1, line)), None, ); - width = self.content.size().0; line += 2; for mailbox_node in a.list_mailboxes() { width = self.content.size().0; @@ -508,7 +222,6 @@ impl Component for AccountStatus { ((1, line), (width - 1, line)), None, ); - width = self.content.size().0; let max_name_width = std::cmp::max( "Server Extensions:".len(), extensions @@ -527,10 +240,9 @@ impl Component for AccountStatus { ((max_name_width + 6, line), (width - 1, line)), None, ); - width = self.content.size().0; line += 1; for (name, status) in extensions.into_iter() { - let (width, height) = self.content.size(); + width = self.content.size().0; write_string_to_grid( name.trim_at_boundary(30), &mut self.content, @@ -541,7 +253,7 @@ impl Component for AccountStatus { None, ); - let (width, height) = self.content.size(); + width = self.content.size().0; let (x, y) = match status { MailBackendExtensionStatus::Unsupported { comment: _ } => write_string_to_grid( "not supported", @@ -684,13 +396,14 @@ impl Component for AccountStatus { ); context.dirty_areas.push_back(area); } + fn process_event(&mut self, event: &mut UIEvent, _context: &mut Context) -> bool { match *event { UIEvent::Resize => { self.dirty = true; } - UIEvent::Input(Key::Left) => { - self.cursor.0 = self.cursor.0.saturating_sub(1); + UIEvent::Input(Key::Left) if self.cursor.0 != 0 => { + self.cursor.0 -= 1; self.dirty = true; return true; } @@ -709,13 +422,21 @@ impl Component for AccountStatus { self.dirty = true; return true; } + UIEvent::MailboxUpdate(_) + | UIEvent::StatusEvent(StatusEvent::NewJob(_)) + | UIEvent::StatusEvent(StatusEvent::JobFinished(_)) + | UIEvent::StatusEvent(StatusEvent::JobCanceled(_)) => { + self.set_dirty(true); + } _ => {} } false } + fn is_dirty(&self) -> bool { self.dirty } + fn set_dirty(&mut self, value: bool) { self.dirty = value; } @@ -723,6 +444,7 @@ impl Component for AccountStatus { fn id(&self) -> ComponentId { self.id } + fn set_id(&mut self, id: ComponentId) { self.id = id; }