override configuration with per-folder configs

This commit is contained in:
Manos Pitsidianakis 2019-09-09 21:38:37 +03:00
parent 81a55abc7c
commit fd38dbed48
No known key found for this signature in database
GPG Key ID: 73627C2F690DF710
3 changed files with 132 additions and 48 deletions

View File

@ -96,6 +96,40 @@ impl ListingTrait for ListingComponent {
} }
} }
impl ListingComponent {
fn set_style(&mut self, new_style: IndexStyle) {
match new_style {
IndexStyle::Plain => {
if let Plain(_) = self {
return;
}
let mut new_l = PlainListing::default();
let coors = self.coordinates();
new_l.set_coordinates((coors.0, coors.1, None));
*self = Plain(new_l);
}
IndexStyle::Threaded => {
if let Threaded(_) = self {
return;
}
let mut new_l = ThreadListing::default();
let coors = self.coordinates();
new_l.set_coordinates((coors.0, coors.1, None));
*self = Threaded(new_l);
}
IndexStyle::Compact => {
if let Compact(_) = self {
return;
}
let mut new_l = CompactListing::default();
let coors = self.coordinates();
new_l.set_coordinates((coors.0, coors.1, None));
*self = Compact(new_l);
}
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct Listing { pub struct Listing {
component: ListingComponent, component: ListingComponent,
@ -226,6 +260,14 @@ impl Component for Listing {
} }
let folder_hash = let folder_hash =
context.accounts[self.cursor_pos.0].folders_order[self.cursor_pos.1]; context.accounts[self.cursor_pos.0].folders_order[self.cursor_pos.1];
/* Check if per-folder configuration overrides general configuration */
if let Some(index_style) = context
.accounts
.get(self.cursor_pos.0)
.and_then(|account| account.folder_confs(folder_hash).conf_override.index)
{
self.component.set_style(index_style);
};
// Inform State that we changed the current folder view. // Inform State that we changed the current folder view.
context context
.replies .replies
@ -258,6 +300,14 @@ impl Component for Listing {
} }
let folder_hash = let folder_hash =
context.accounts[self.cursor_pos.0].folders_order[self.cursor_pos.1]; context.accounts[self.cursor_pos.0].folders_order[self.cursor_pos.1];
/* Check if per-folder configuration overrides general configuration */
if let Some(index_style) = context
.accounts
.get(self.cursor_pos.0)
.and_then(|account| account.folder_confs(folder_hash).conf_override.index)
{
self.component.set_style(index_style);
};
// Inform State that we changed the current folder view. // Inform State that we changed the current folder view.
context context
.replies .replies
@ -266,30 +316,15 @@ impl Component for Listing {
} }
UIEvent::Action(ref action) => match action { UIEvent::Action(ref action) => match action {
Action::Listing(ListingAction::SetPlain) => { Action::Listing(ListingAction::SetPlain) => {
if let Plain(_) = self.component { self.component.set_style(IndexStyle::Plain);
return true;
}
let mut new_l = PlainListing::default();
new_l.set_coordinates((self.cursor_pos.0, self.cursor_pos.1, None));
self.component = Plain(new_l);
return true; return true;
} }
Action::Listing(ListingAction::SetThreaded) => { Action::Listing(ListingAction::SetThreaded) => {
if let Threaded(_) = self.component { self.component.set_style(IndexStyle::Threaded);
return true;
}
let mut new_l = ThreadListing::default();
new_l.set_coordinates((self.cursor_pos.0, self.cursor_pos.1, None));
self.component = Threaded(new_l);
return true; return true;
} }
Action::Listing(ListingAction::SetCompact) => { Action::Listing(ListingAction::SetCompact) => {
if let Compact(_) = self.component { self.component.set_style(IndexStyle::Compact);
return true;
}
let mut new_l = CompactListing::default();
new_l.set_coordinates((self.cursor_pos.0, self.cursor_pos.1, None));
self.component = Compact(new_l);
return true; return true;
} }
_ => {} _ => {}
@ -437,7 +472,7 @@ impl From<IndexStyle> for ListingComponent {
impl Listing { impl Listing {
const DESCRIPTION: &'static str = "listing"; const DESCRIPTION: &'static str = "listing";
pub fn new(accounts: &[Account]) -> Self { pub fn new(accounts: &[Account]) -> Self {
let accounts = accounts let account_entries = accounts
.iter() .iter()
.enumerate() .enumerate()
.map(|(i, a)| AccountMenuEntry { .map(|(i, a)| AccountMenuEntry {
@ -445,9 +480,20 @@ impl Listing {
index: i, index: i,
}) })
.collect(); .collect();
/* Check if per-folder configuration overrides general configuration */
let component = if let Some(index_style) = accounts.get(0).and_then(|account| {
account
.folders_order
.get(0)
.and_then(|folder_hash| account.folder_confs(*folder_hash).conf_override.index)
}) {
ListingComponent::from(index_style)
} else {
Compact(Default::default())
};
Listing { Listing {
component: Compact(Default::default()), component,
accounts, accounts: account_entries,
visible: true, visible: true,
dirty: true, dirty: true,
cursor_pos: (0, 0), cursor_pos: (0, 0),

View File

@ -89,17 +89,29 @@ impl ToggleFlag {
} }
} }
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct MailUIConf {
pub pager: Option<PagerSettings>,
pub notifications: Option<NotificationsSettings>,
pub shortcuts: Option<Shortcuts>,
pub mailer: Option<MailerSettings>,
pub identity: Option<String>,
pub index: Option<IndexStyle>,
}
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FolderConf { pub struct FolderConf {
rename: Option<String>, pub rename: Option<String>,
#[serde(default = "true_val")] #[serde(default = "true_val")]
autoload: bool, pub autoload: bool,
#[serde(deserialize_with = "toggleflag_de", default)] #[serde(deserialize_with = "toggleflag_de", default)]
subscribe: ToggleFlag, pub subscribe: ToggleFlag,
#[serde(deserialize_with = "toggleflag_de", default)] #[serde(deserialize_with = "toggleflag_de", default)]
ignore: ToggleFlag, pub ignore: ToggleFlag,
#[serde(default = "none")] #[serde(default = "none")]
usage: Option<SpecialUseMailbox>, pub usage: Option<SpecialUseMailbox>,
#[serde(flatten)]
pub conf_override: MailUIConf,
} }
impl Default for FolderConf { impl Default for FolderConf {
@ -108,8 +120,9 @@ impl Default for FolderConf {
rename: None, rename: None,
autoload: true, autoload: true,
subscribe: ToggleFlag::Unset, subscribe: ToggleFlag::Unset,
ignore: ToggleFlag::False, ignore: ToggleFlag::Unset,
usage: None, usage: None,
conf_override: MailUIConf::default(),
} }
} }
} }
@ -132,7 +145,6 @@ pub struct FileAccount {
#[serde(default = "none")] #[serde(default = "none")]
display_name: Option<String>, display_name: Option<String>,
#[serde(deserialize_with = "index_from_str")]
index: IndexStyle, index: IndexStyle,
/// A command to pipe html output before displaying it in a pager /// A command to pipe html output before displaying it in a pager
@ -197,7 +209,10 @@ impl From<FileAccount> for AccountConf {
} }
if folder_confs[s].usage.is_none() { if folder_confs[s].usage.is_none() {
let name = s.split('/').last().unwrap_or(""); let name = s
.split(if s.contains('/') { '/' } else { '.' })
.last()
.unwrap_or("");
folder_confs.get_mut(s).unwrap().usage = if name.eq_ignore_ascii_case("inbox") { folder_confs.get_mut(s).unwrap().usage = if name.eq_ignore_ascii_case("inbox") {
Some(SpecialUseMailbox::Inbox) Some(SpecialUseMailbox::Inbox)
} else if name.eq_ignore_ascii_case("archive") { } else if name.eq_ignore_ascii_case("archive") {
@ -265,9 +280,9 @@ struct FileSettings {
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct AccountConf { pub struct AccountConf {
account: AccountSettings, pub(crate) account: AccountSettings,
conf: FileAccount, pub(crate) conf: FileAccount,
folder_confs: HashMap<String, FolderConf>, pub(crate) folder_confs: HashMap<String, FolderConf>,
} }
impl AccountConf { impl AccountConf {
@ -380,7 +395,7 @@ impl Settings {
} }
} }
#[derive(Copy, Debug, Clone, Serialize, Deserialize)] #[derive(Copy, Debug, Clone, Hash, PartialEq)]
pub enum IndexStyle { pub enum IndexStyle {
Plain, Plain,
Threaded, Threaded,
@ -393,19 +408,6 @@ impl Default for IndexStyle {
} }
} }
fn index_from_str<'de, D>(deserializer: D) -> std::result::Result<IndexStyle, D::Error>
where
D: Deserializer<'de>,
{
let s = <String>::deserialize(deserializer)?;
match s.as_str() {
"Plain" | "plain" => Ok(IndexStyle::Plain),
"Threaded" | "threaded" => Ok(IndexStyle::Threaded),
"Compact" | "compact" => Ok(IndexStyle::Compact),
_ => Err(de::Error::custom("invalid `index` value")),
}
}
fn non_empty_string<'de, D>(deserializer: D) -> std::result::Result<Option<String>, D::Error> fn non_empty_string<'de, D>(deserializer: D) -> std::result::Result<Option<String>, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
@ -468,3 +470,31 @@ mod default_vals {
None None
} }
} }
impl<'de> Deserialize<'de> for IndexStyle {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = <String>::deserialize(deserializer)?;
match s.as_str() {
"Plain" | "plain" => Ok(IndexStyle::Plain),
"Threaded" | "threaded" => Ok(IndexStyle::Threaded),
"Compact" | "compact" => Ok(IndexStyle::Compact),
_ => Err(de::Error::custom("invalid `index` value")),
}
}
}
impl Serialize for IndexStyle {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
IndexStyle::Plain => serializer.serialize_str("plain"),
IndexStyle::Threaded => serializer.serialize_str("threaded"),
IndexStyle::Compact => serializer.serialize_str("compact"),
}
}
}

View File

@ -23,7 +23,7 @@
* Account management from user configuration. * Account management from user configuration.
*/ */
use super::AccountConf; use super::{AccountConf, FolderConf};
use fnv::FnvHashMap; use fnv::FnvHashMap;
use melib::async_workers::{Async, AsyncBuilder, AsyncStatus}; use melib::async_workers::{Async, AsyncBuilder, AsyncStatus};
use melib::backends::{ use melib::backends::{
@ -116,8 +116,9 @@ impl MailboxEntry {
pub struct Account { pub struct Account {
name: String, name: String,
pub(crate) folders: FnvHashMap<FolderHash, MailboxEntry>, pub(crate) folders: FnvHashMap<FolderHash, MailboxEntry>,
pub(crate) folder_confs: FnvHashMap<FolderHash, FolderConf>,
pub(crate) folders_order: Vec<FolderHash>, pub(crate) folders_order: Vec<FolderHash>,
folder_names: FnvHashMap<FolderHash, String>, pub(crate) folder_names: FnvHashMap<FolderHash, String>,
tree: Vec<FolderNode>, tree: Vec<FolderNode>,
sent_folder: Option<FolderHash>, sent_folder: Option<FolderHash>,
pub(crate) collection: Collection, pub(crate) collection: Collection,
@ -205,6 +206,7 @@ impl Account {
let mut workers: FnvHashMap<FolderHash, Worker> = FnvHashMap::default(); let mut workers: FnvHashMap<FolderHash, Worker> = FnvHashMap::default();
let notify_fn = Arc::new(notify_fn); let notify_fn = Arc::new(notify_fn);
let mut folder_names = FnvHashMap::default(); let mut folder_names = FnvHashMap::default();
let mut folder_confs = FnvHashMap::default();
let mut sent_folder = None; let mut sent_folder = None;
for f in ref_folders.values_mut() { for f in ref_folders.values_mut() {
@ -221,6 +223,7 @@ impl Account {
} }
_ => {} _ => {}
} }
folder_confs.insert(f.hash(), settings.folder_confs[f.path()].clone());
folder_names.insert(f.hash(), f.path().to_string()); folder_names.insert(f.hash(), f.path().to_string());
} }
@ -300,6 +303,7 @@ impl Account {
Account { Account {
name, name,
folders, folders,
folder_confs,
folders_order, folders_order,
folder_names, folder_names,
tree, tree,
@ -669,6 +673,10 @@ impl Account {
pub fn folder_operation(&mut self, path: &str, op: FolderOperation) -> Result<()> { pub fn folder_operation(&mut self, path: &str, op: FolderOperation) -> Result<()> {
self.backend.folder_operation(path, op) self.backend.folder_operation(path, op)
} }
pub fn folder_confs(&self, folder_hash: FolderHash) -> &FolderConf {
&self.folder_confs[&folder_hash]
}
} }
impl Index<FolderHash> for Account { impl Index<FolderHash> for Account {