Open sidebar for mailbox navigation with Left/Right arrow keys

Left/Right arrow keys change focus between the sidebar and mailbox
listing. If focused on sidebar, move arrow keys to select mailbox and
open with 'Enter'. Press Right arrow key to return to mailbox listing.

- Mailbox focused:
  +--+-------------+
  |~ |=============|
  |~ |=============|
  |  |=============|
  |~ |=============|
  |~ |=============|
  +--+-------------+
- Press `Left` arrow key
- Menu focused:
  +--------+-------+
  |~~~~    |=======|
  |~~      |=======|
  |        |=======|
  |~~~     |=======|
  |~~~~    |=======|
  +--------+-------+
- Press `Right` arrow key to return
memfd
Manos Pitsidianakis 2020-04-04 19:10:06 +03:00
parent 840005022c
commit fd60be482f
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
2 changed files with 460 additions and 266 deletions

View File

@ -310,6 +310,12 @@ impl ListingComponent {
}
}
#[derive(PartialEq, Debug)]
enum ListingFocus {
Menu,
Mailbox,
}
#[derive(Debug)]
pub struct Listing {
component: ListingComponent,
@ -317,6 +323,7 @@ pub struct Listing {
dirty: bool,
visible: bool,
cursor_pos: (usize, usize),
menu_cursor_pos: (usize, usize),
startup_checks_rate: RateLimit,
id: ComponentId,
theme_default: ThemeAttribute,
@ -326,6 +333,7 @@ pub struct Listing {
cmd_buf: String,
/// This is the width of the right container to the entire width.
ratio: usize, // right/(container width) * 100
focus: ListingFocus,
}
impl fmt::Display for Listing {
@ -513,12 +521,18 @@ impl Component for Listing {
_ => {}
}
if self.component.process_event(event, context) {
if self.focus == ListingFocus::Mailbox && self.component.process_event(event, context) {
return true;
}
let shortcuts = self.get_shortcuts(context);
if self.focus == ListingFocus::Mailbox {
match *event {
UIEvent::Input(Key::Left) => {
self.focus = ListingFocus::Menu;
self.ratio = 50;
self.set_dirty(true);
}
UIEvent::Input(ref k)
if shortcut!(k == shortcuts[Listing::DESCRIPTION]["next_mailbox"])
|| shortcut!(k == shortcuts[Listing::DESCRIPTION]["prev_mailbox"]) =>
@ -771,19 +785,13 @@ impl Component for Listing {
return true;
}
UIEvent::Input(ref k)
if shortcut!(k == shortcuts[Listing::DESCRIPTION]["toggle_menu_visibility"]) =>
if shortcut!(
k == shortcuts[Listing::DESCRIPTION]["toggle_menu_visibility"]
) =>
{
self.menu_visibility = !self.menu_visibility;
self.set_dirty(true);
}
UIEvent::Input(ref k)
if shortcut!(k == shortcuts[Listing::DESCRIPTION]["new_mail"]) =>
{
context
.replies
.push_back(UIEvent::Action(Tab(NewDraft(self.cursor_pos.0, None))));
return true;
}
UIEvent::Input(ref key)
if shortcut!(key == shortcuts[Listing::DESCRIPTION]["search"]) =>
{
@ -818,6 +826,186 @@ impl Component for Listing {
}
return true;
}
_ => {}
}
} else if self.focus == ListingFocus::Menu {
match *event {
UIEvent::Input(Key::Right) => {
self.focus = ListingFocus::Mailbox;
self.ratio = 90;
self.set_dirty(true);
return true;
}
UIEvent::Input(ref k)
if shortcut!(k == shortcuts[CompactListing::DESCRIPTION]["open_thread"]) =>
{
self.cursor_pos = self.menu_cursor_pos;
self.change_account(context);
self.focus = ListingFocus::Mailbox;
self.ratio = 90;
self.set_dirty(true);
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
self.get_status(context),
)));
return true;
}
UIEvent::Input(ref k)
if shortcut!(k == shortcuts[Listing::DESCRIPTION]["scroll_up"])
|| shortcut!(k == shortcuts[Listing::DESCRIPTION]["scroll_down"]) =>
{
let mut amount = if self.cmd_buf.is_empty() {
1
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear();
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
amount
} else {
self.cmd_buf.clear();
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
return true;
};
if shortcut!(k == shortcuts[Listing::DESCRIPTION]["scroll_up"]) {
while amount > 0 {
if self.menu_cursor_pos.1 > 0 {
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);
} else {
return true;
}
amount -= 1;
}
} else if shortcut!(k == shortcuts[Listing::DESCRIPTION]["scroll_down"]) {
while amount > 0 {
if self.menu_cursor_pos.1 + 1
< self.accounts[self.menu_cursor_pos.0].entries.len()
{
self.menu_cursor_pos.1 += 1;
} else if self.menu_cursor_pos.0 + 1 < self.accounts.len() {
self.menu_cursor_pos.0 += 1;
self.menu_cursor_pos.1 = 0;
} else {
return true;
}
amount -= 1;
}
}
self.set_dirty(true);
return true;
}
UIEvent::Input(ref k)
if shortcut!(k == shortcuts[Listing::DESCRIPTION]["next_mailbox"])
|| shortcut!(k == shortcuts[Listing::DESCRIPTION]["prev_mailbox"]) =>
{
let amount = if self.cmd_buf.is_empty() {
1
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear();
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
amount
} else {
self.cmd_buf.clear();
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
return true;
};
match k {
k if shortcut!(k == shortcuts[Listing::DESCRIPTION]["next_mailbox"]) => {
if let Some((_, mailbox_hash)) = self.accounts[self.menu_cursor_pos.0]
.entries
.get(self.menu_cursor_pos.1 + amount)
{
self.menu_cursor_pos.1 += amount;
self.set_dirty(true);
} else {
return true;
}
}
k if shortcut!(k == shortcuts[Listing::DESCRIPTION]["prev_mailbox"]) => {
if self.cursor_pos.1 >= amount {
if let Some((_, mailbox_hash)) = self.accounts
[self.menu_cursor_pos.0]
.entries
.get(self.menu_cursor_pos.1 - amount)
{
self.menu_cursor_pos.1 -= amount;
self.set_dirty(true);
} else {
return true;
}
} else {
return true;
}
}
_ => {}
}
return true;
}
UIEvent::Input(ref k)
if shortcut!(k == shortcuts[Listing::DESCRIPTION]["next_account"])
|| shortcut!(k == shortcuts[Listing::DESCRIPTION]["prev_account"]) =>
{
let amount = if self.cmd_buf.is_empty() {
1
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
self.cmd_buf.clear();
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
amount
} else {
self.cmd_buf.clear();
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
return true;
};
match k {
k if shortcut!(k == shortcuts[Listing::DESCRIPTION]["next_account"]) => {
if self.menu_cursor_pos.0 + amount < self.accounts.len() {
self.menu_cursor_pos = (self.menu_cursor_pos.0 + amount, 0);
} else {
return true;
}
}
k if shortcut!(k == shortcuts[Listing::DESCRIPTION]["prev_account"]) => {
if self.menu_cursor_pos.0 >= amount {
self.menu_cursor_pos = (self.menu_cursor_pos.0 - amount, 0);
} else {
return true;
}
}
_ => return false,
}
self.set_dirty(true);
return true;
}
_ => {}
}
}
match *event {
UIEvent::Input(ref k)
if shortcut!(k == shortcuts[Listing::DESCRIPTION]["new_mail"]) =>
{
context
.replies
.push_back(UIEvent::Action(Tab(NewDraft(self.cursor_pos.0, None))));
return true;
}
UIEvent::StartupCheck(_) => {
self.dirty = true;
context
@ -945,12 +1133,14 @@ impl Listing {
visible: true,
dirty: true,
cursor_pos: (0, 0),
menu_cursor_pos: (0, 0),
startup_checks_rate: RateLimit::new(2, 1000),
theme_default: conf::value(context, "theme_default"),
id: ComponentId::new_v4(),
show_divider: false,
menu_visibility: true,
ratio: 90,
focus: ListingFocus::Mailbox,
cmd_buf: String::with_capacity(4),
};
ret.change_account(context);
@ -1006,7 +1196,9 @@ impl Listing {
let upper_left = upper_left!(area);
let bottom_right = bottom_right!(area);
let must_highlight_account: bool = self.cursor_pos.0 == a.index;
let must_highlight_account: bool = (self.focus == ListingFocus::Mailbox
&& self.cursor_pos.0 == a.index)
|| (self.focus == ListingFocus::Menu && self.menu_cursor_pos.0 == a.index);
let mut lines: Vec<(usize, usize, MailboxHash, Option<usize>)> = Vec::new();
@ -1060,7 +1252,9 @@ impl Listing {
break;
}
let (att, index_att, unread_count_att) = if must_highlight_account {
if self.cursor_pos.1 == idx {
if (self.focus == ListingFocus::Mailbox && self.cursor_pos.1 == idx)
|| (self.focus == ListingFocus::Menu && self.menu_cursor_pos.1 == idx)
{
let mut ret = (
crate::conf::value(context, "mail.sidebar_highlighted"),
crate::conf::value(context, "mail.sidebar_highlighted_index"),

View File

@ -618,7 +618,7 @@ impl fmt::Display for CompactListing {
}
impl CompactListing {
const DESCRIPTION: &'static str = "compact listing";
pub const DESCRIPTION: &'static str = "compact listing";
pub fn new(coordinates: (usize, MailboxHash)) -> Self {
CompactListing {
cursor_pos: (0, 1, 0),