accounts: add default_mailbox setting

Add a default mailbox setting:

> The mailbox that is the default to open / view for this account. Must be
> a valid mailbox name.
>
> If not specified, the default is [`Self::root_mailbox`].

Closes: #350
Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
pull/370/head
Manos Pitsidianakis 2 months ago
parent 742f038f74
commit 4e941a9e8b
No known key found for this signature in database
GPG Key ID: 7729C7707F7E09D0

@ -217,6 +217,11 @@ Default values are shown in parentheses.
The backend-specific path of the root_mailbox, usually The backend-specific path of the root_mailbox, usually
.Sy INBOX Ns .Sy INBOX Ns
\&. \&.
.It Ic default_mailbox Ar String
.Pq Em optional
The mailbox that is the default to open or view for this account.
Must be a valid mailbox path.
If not specified, the default will be the root mailbox.
.It Ic format Ar String Op maildir mbox imap notmuch jmap .It Ic format Ar String Op maildir mbox imap notmuch jmap
The format of the mail backend. The format of the mail backend.
.It Ic subscribed_mailboxes Ar [String,] .It Ic subscribed_mailboxes Ar [String,]

@ -350,9 +350,19 @@ impl Account {
.keys() .keys()
.cloned() .cloned()
.collect::<HashSet<String>>(); .collect::<HashSet<String>>();
let mut default_mailbox = self
.settings
.conf
.default_mailbox
.clone()
.into_iter()
.collect::<HashSet<String>>();
for f in ref_mailboxes.values_mut() { for f in ref_mailboxes.values_mut() {
if let Some(conf) = self.settings.mailbox_confs.get_mut(f.path()) { if let Some(conf) = self.settings.mailbox_confs.get_mut(f.path()) {
mailbox_conf_hash_set.remove(f.path()); mailbox_conf_hash_set.remove(f.path());
if default_mailbox.remove(f.path()) {
self.settings.default_mailbox = Some(f.hash());
}
conf.mailbox_conf.usage = if f.special_usage() != SpecialUsageMailbox::Normal { conf.mailbox_conf.usage = if f.special_usage() != SpecialUsageMailbox::Normal {
Some(f.special_usage()) Some(f.special_usage())
} else { } else {
@ -447,6 +457,23 @@ impl Account {
))); )));
} }
match self.settings.conf.default_mailbox {
Some(ref v) if !default_mailbox.is_empty() => {
let err = Error::new(format!(
"Account `{}` has default mailbox set as `{}` but it doesn't exist.",
&self.name, v
))
.set_kind(ErrorKind::Configuration);
self.is_online.set_err(err.clone());
self.main_loop_handler
.send(ThreadEvent::UIEvent(UIEvent::AccountStatusChange(
self.hash, None,
)));
return Err(err);
}
_ => {}
}
let mut tree: Vec<MailboxNode> = Vec::new(); let mut tree: Vec<MailboxNode> = Vec::new();
for (h, f) in ref_mailboxes.iter() { for (h, f) in ref_mailboxes.iter() {
if !f.is_subscribed() { if !f.is_subscribed() {
@ -1394,6 +1421,12 @@ impl Account {
} }
} }
pub fn default_mailbox(&self) -> Option<MailboxHash> {
self.settings
.default_mailbox
.or_else(|| Some(*self.mailboxes_order.first()?))
}
pub fn mailbox_by_path(&self, path: &str) -> Result<MailboxHash> { pub fn mailbox_by_path(&self, path: &str) -> Result<MailboxHash> {
if let Some((mailbox_hash, _)) = self if let Some((mailbox_hash, _)) = self
.mailbox_entries .mailbox_entries

@ -165,6 +165,12 @@ use crate::conf::deserializers::extra_settings;
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct FileAccount { pub struct FileAccount {
pub root_mailbox: String, pub root_mailbox: String,
/// The mailbox that is the default to open / view for this account. Must be
/// a valid mailbox path.
///
/// If not specified, the default is [`Self::root_mailbox`].
#[serde(default = "none", skip_serializing_if = "Option::is_none")]
pub default_mailbox: Option<String>,
pub format: String, pub format: String,
pub identity: String, pub identity: String,
#[serde(default)] #[serde(default)]
@ -234,6 +240,7 @@ pub struct FileSettings {
#[derive(Clone, Debug, Default, Serialize)] #[derive(Clone, Debug, Default, Serialize)]
pub struct AccountConf { pub struct AccountConf {
pub account: AccountSettings, pub account: AccountSettings,
pub default_mailbox: Option<MailboxHash>,
pub sent_mailbox: Option<MailboxHash>, pub sent_mailbox: Option<MailboxHash>,
pub conf: FileAccount, pub conf: FileAccount,
pub conf_override: MailUIConf, pub conf_override: MailUIConf,
@ -286,6 +293,7 @@ impl From<FileAccount> for AccountConf {
let mailbox_confs = x.mailboxes.clone(); let mailbox_confs = x.mailboxes.clone();
Self { Self {
account: acc, account: acc,
default_mailbox: None,
sent_mailbox: None, sent_mailbox: None,
conf_override: x.conf_override.clone(), conf_override: x.conf_override.clone(),
conf: x, conf: x,
@ -538,6 +546,7 @@ This is required so that you don't accidentally start meli and find out later th
mailboxes, mailboxes,
extra, extra,
manual_refresh, manual_refresh,
default_mailbox: _,
refresh_command: _, refresh_command: _,
search_backend: _, search_backend: _,
conf_override: _, conf_override: _,

@ -475,6 +475,18 @@ struct AccountMenuEntry {
entries: SmallVec<[MailboxMenuEntry; 16]>, entries: SmallVec<[MailboxMenuEntry; 16]>,
} }
impl AccountMenuEntry {
fn entry_by_hash(&self, needle: MailboxHash) -> Option<usize> {
self.entries.iter().enumerate().find_map(|(i, e)| {
if e.mailbox_hash == needle {
Some(i)
} else {
None
}
})
}
}
pub trait MailListingTrait: ListingTrait { pub trait MailListingTrait: ListingTrait {
fn as_component(&self) -> &dyn Component fn as_component(&self) -> &dyn Component
where where
@ -1568,7 +1580,15 @@ impl Component for Listing {
k if shortcut!(k == shortcuts[Shortcuts::LISTING]["next_account"]) => { k if shortcut!(k == shortcuts[Shortcuts::LISTING]["next_account"]) => {
if self.cursor_pos.account + amount < self.accounts.len() { if self.cursor_pos.account + amount < self.accounts.len() {
self.cursor_pos.account += amount; self.cursor_pos.account += amount;
self.cursor_pos.menu = MenuEntryCursor::Mailbox(0); let _new_val = self.cursor_pos.account;
self.cursor_pos.menu = if let Some(idx) = context.accounts[_new_val]
.default_mailbox()
.and_then(|h| self.accounts[_new_val].entry_by_hash(h))
{
MenuEntryCursor::Mailbox(idx)
} else {
MenuEntryCursor::Status
};
} else { } else {
return true; return true;
} }
@ -1576,7 +1596,15 @@ impl Component for Listing {
k if shortcut!(k == shortcuts[Shortcuts::LISTING]["prev_account"]) => { k if shortcut!(k == shortcuts[Shortcuts::LISTING]["prev_account"]) => {
if self.cursor_pos.account >= amount { if self.cursor_pos.account >= amount {
self.cursor_pos.account -= amount; self.cursor_pos.account -= amount;
self.cursor_pos.menu = MenuEntryCursor::Mailbox(0); let _new_val = self.cursor_pos.account;
self.cursor_pos.menu = if let Some(idx) = context.accounts[_new_val]
.default_mailbox()
.and_then(|h| self.accounts[_new_val].entry_by_hash(h))
{
MenuEntryCursor::Mailbox(idx)
} else {
MenuEntryCursor::Status
};
} else { } else {
return true; return true;
} }
@ -2076,9 +2104,17 @@ impl Component for Listing {
} => { } => {
if *account > 0 { if *account > 0 {
*account -= 1; *account -= 1;
self.menu_cursor_pos.menu = MenuEntryCursor::Mailbox( self.menu_cursor_pos.menu =
self.accounts[*account].entries.len().saturating_sub(1), if self.accounts[*account].entries.is_empty() {
); MenuEntryCursor::Status
} else {
MenuEntryCursor::Mailbox(
self.accounts[*account]
.entries
.len()
.saturating_sub(1),
)
};
} else { } else {
return true; return true;
} }
@ -2111,7 +2147,12 @@ impl Component for Listing {
} if !self.accounts[*account].entries.is_empty() } if !self.accounts[*account].entries.is_empty()
&& *menu == MenuEntryCursor::Status => && *menu == MenuEntryCursor::Status =>
{ {
*menu = MenuEntryCursor::Mailbox(0); if let Some(idx) = context.accounts[*account]
.default_mailbox()
.and_then(|h| self.accounts[*account].entry_by_hash(h))
{
*menu = MenuEntryCursor::Mailbox(idx);
}
} }
// If current account has no mailboxes, go to next account // If current account has no mailboxes, go to next account
CursorPos { CursorPos {
@ -2250,15 +2291,32 @@ impl Component for Listing {
{ {
if self.menu_cursor_pos.account + amount >= self.accounts.len() { if self.menu_cursor_pos.account + amount >= self.accounts.len() {
// Go to last mailbox. // Go to last mailbox.
self.menu_cursor_pos.menu = MenuEntryCursor::Mailbox( self.menu_cursor_pos.menu = if self.accounts
self.accounts[self.menu_cursor_pos.account] [self.menu_cursor_pos.account]
.entries .entries
.len() .is_empty()
.saturating_sub(1), {
); MenuEntryCursor::Status
} else {
MenuEntryCursor::Mailbox(
self.accounts[self.menu_cursor_pos.account]
.entries
.len()
.saturating_sub(1),
)
};
} else if self.menu_cursor_pos.account + amount < self.accounts.len() { } else if self.menu_cursor_pos.account + amount < self.accounts.len() {
self.menu_cursor_pos.account += amount; self.menu_cursor_pos.account += amount;
self.menu_cursor_pos.menu = MenuEntryCursor::Mailbox(0); let _new_val = self.menu_cursor_pos.account;
self.menu_cursor_pos.menu = if let Some(idx) = context.accounts
[_new_val]
.default_mailbox()
.and_then(|h| self.accounts[_new_val].entry_by_hash(h))
{
MenuEntryCursor::Mailbox(idx)
} else {
MenuEntryCursor::Status
};
} else { } else {
return true; return true;
} }
@ -2268,7 +2326,16 @@ impl Component for Listing {
{ {
if self.menu_cursor_pos.account >= amount { if self.menu_cursor_pos.account >= amount {
self.menu_cursor_pos.account -= amount; self.menu_cursor_pos.account -= amount;
self.menu_cursor_pos.menu = MenuEntryCursor::Mailbox(0); let _new_val = self.menu_cursor_pos.account;
self.menu_cursor_pos.menu = if let Some(idx) = context.accounts
[_new_val]
.default_mailbox()
.and_then(|h| self.accounts[_new_val].entry_by_hash(h))
{
MenuEntryCursor::Mailbox(idx)
} else {
MenuEntryCursor::Status
};
} else { } else {
return true; return true;
} }
@ -2294,12 +2361,24 @@ impl Component for Listing {
menu: MenuEntryCursor::Mailbox(0) menu: MenuEntryCursor::Mailbox(0)
} }
) { ) {
// Can't go anywhere upwards, we're on top already.
return true; return true;
} }
if self.menu_cursor_pos.menu == MenuEntryCursor::Mailbox(0) { match (
self.menu_cursor_pos.account = 0; self.menu_cursor_pos.menu,
} else { context.accounts[self.menu_cursor_pos.account]
self.menu_cursor_pos.menu = MenuEntryCursor::Mailbox(0); .default_mailbox()
.and_then(|h| {
self.accounts[self.menu_cursor_pos.account].entry_by_hash(h)
}),
) {
(MenuEntryCursor::Mailbox(0), _) => {
self.menu_cursor_pos.account = 0;
}
(MenuEntryCursor::Mailbox(_), Some(v)) => {
self.menu_cursor_pos.menu = MenuEntryCursor::Mailbox(v);
}
_ => return true,
} }
if self.show_menu_scrollbar != ShowMenuScrollbar::Never { if self.show_menu_scrollbar != ShowMenuScrollbar::Never {
self.menu_scrollbar_show_timer.rearm(); self.menu_scrollbar_show_timer.rearm();
@ -2337,11 +2416,20 @@ impl Component for Listing {
self.accounts[*account].entries.len().saturating_sub(1) self.accounts[*account].entries.len().saturating_sub(1)
) { ) {
*account = self.accounts.len().saturating_sub(1); *account = self.accounts.len().saturating_sub(1);
*menu = MenuEntryCursor::Mailbox(0); *menu = if let Some(idx) = context.accounts[*account]
} else { .default_mailbox()
.and_then(|h| self.accounts[*account].entry_by_hash(h))
{
MenuEntryCursor::Mailbox(idx)
} else {
MenuEntryCursor::Status
};
} else if !self.accounts[*account].entries.is_empty() {
*menu = MenuEntryCursor::Mailbox( *menu = MenuEntryCursor::Mailbox(
self.accounts[*account].entries.len().saturating_sub(1), self.accounts[*account].entries.len().saturating_sub(1),
); );
} else {
*menu = MenuEntryCursor::Status;
} }
if self.show_menu_scrollbar != ShowMenuScrollbar::Never { if self.show_menu_scrollbar != ShowMenuScrollbar::Never {
self.menu_scrollbar_show_timer.rearm(); self.menu_scrollbar_show_timer.rearm();

Loading…
Cancel
Save