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
parent
742f038f74
commit
4e941a9e8b
|
@ -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…
Reference in New Issue