ui: select `From` identities in compose tab

Tracking issue #24
embed
Manos Pitsidianakis 2018-08-30 15:54:30 +03:00
parent d8f81cb596
commit a20e7ac5c2
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
5 changed files with 169 additions and 59 deletions

View File

@ -25,6 +25,8 @@ pub struct AccountSettings {
pub root_folder: String,
pub format: String,
pub sent_folder: String,
pub identity: String,
pub display_name: Option<String>,
}
impl AccountSettings {
@ -34,7 +36,16 @@ impl AccountSettings {
pub fn name(&self) -> &str {
&self.name
}
pub fn set_name(&mut self, s: String) {
self.name = s;
}
pub fn root_folder(&self) -> &str {
&self.root_folder
}
pub fn identity(&self) -> &str {
&self.identity
}
pub fn display_name(&self) -> Option<&String> {
self.display_name.as_ref()
}
}

View File

@ -40,6 +40,9 @@ impl Default for Draft {
}
impl Draft {
pub fn headers_mut(&mut self) -> &mut FnvHashMap<String, String> {
&mut self.headers
}
pub fn headers(&self) -> &FnvHashMap<String, String> {
&self.headers
}

View File

@ -25,10 +25,13 @@ use melib::Draft;
#[derive(Debug)]
pub struct Composer {
dirty: bool,
mode: ViewMode,
pager: Pager,
draft: Draft,
account_cursor: usize,
dirty: bool,
}
impl Default for Composer {
@ -36,8 +39,9 @@ impl Default for Composer {
Composer {
dirty: true,
mode: ViewMode::Overview,
pager: Pager::from_str("", None),
pager: Pager::default(),
draft: Draft::default(),
account_cursor: 0,
}
}
}
@ -55,9 +59,79 @@ impl fmt::Display for Composer {
}
}
impl Composer {
fn draw_header_table(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
let upper_left = upper_left!(area);
let bottom_right = bottom_right!(area);
let headers = self.draft.headers();
{
let (mut x, mut y) = upper_left;
for k in &["Date", "From", "To", "Subject"] {
let update = {
let (x, y) = write_string_to_grid(
k,
grid,
Color::Default,
Color::Default,
((x, y), set_y(bottom_right, y)),
true,
);
let (x, y) = write_string_to_grid(
": ",
grid,
Color::Default,
Color::Default,
((x, y), set_y(bottom_right, y)),
true,
);
let (x, y) = if k == &"From" {
write_string_to_grid(
"",
grid,
Color::Byte(251),
Color::Default,
((x, y), set_y(bottom_right, y)),
true,
)
} else {
(x, y)
};
let (x, y) = write_string_to_grid(
&headers[*k],
grid,
Color::Default,
Color::Default,
((x, y), set_y(bottom_right, y)),
true,
);
if k == &"From" {
write_string_to_grid(
"",
grid,
Color::Byte(251),
Color::Default,
((x, y), set_y(bottom_right, y)),
true,
)
} else {
(x, y)
}
};
x = get_x(upper_left);
y = update.1 + 1;
}
}
}
}
impl Component for Composer {
fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
if self.dirty {
self.draft.headers_mut().insert(
"From".into(),
get_display_name(context, self.account_cursor),
);
clear_area(grid, area);
}
let upper_left = upper_left!(area);
@ -93,6 +167,7 @@ impl Component for Composer {
}
}
let header_area = (set_x(upper_left, mid + 1), (mid + 78, header_height + 1));
let body_area = (
(mid + 1, header_height + 2),
(mid + 78, get_y(bottom_right)),
@ -104,40 +179,7 @@ impl Component for Composer {
}
match self.mode {
ViewMode::Overview => {
let headers = self.draft.headers();
{
let (mut x, mut y) = set_x(upper_left, mid + 1);
for k in &["Date", "From", "To", "Subject"] {
let update = {
let (x, y) = write_string_to_grid(
k,
grid,
Color::Default,
Color::Default,
((x, y), (mid + 78, y)),
true,
);
let (x, y) = write_string_to_grid(
": ",
grid,
Color::Default,
Color::Default,
((x, y), (mid + 78, y)),
true,
);
write_string_to_grid(
&headers[*k],
grid,
Color::Default,
Color::Default,
((x, y), (mid + 78, y)),
true,
)
};
x = mid + 1;
y = update.1 + 1;
}
}
self.draw_header_table(grid, header_area, context);
self.pager.draw(grid, body_area, context);
}
}
@ -152,6 +194,26 @@ impl Component for Composer {
UIEventType::Resize => {
self.dirty = true;
}
UIEventType::Input(Key::Left) => {
self.account_cursor = self.account_cursor.saturating_sub(1);
self.draft.headers_mut().insert(
"From".into(),
get_display_name(context, self.account_cursor),
);
self.dirty = true;
return true;
}
UIEventType::Input(Key::Right) => {
if self.account_cursor + 1 < context.accounts.len() {
self.account_cursor += 1;
self.draft.headers_mut().insert(
"From".into(),
get_display_name(context, self.account_cursor),
);
self.dirty = true;
}
return true;
}
UIEventType::Input(Key::Char('\n')) => {
use std::process::{Command, Stdio};
/* Kill input thread so that spawned command can be sole receiver of stdin */
@ -177,6 +239,16 @@ impl Component for Composer {
self.dirty = true;
return true;
}
UIEventType::Input(Key::Char('m')) => {
let mut f =
create_temp_file(self.draft.to_string().unwrap().as_str().as_bytes(), None);
context.replies.push_back(UIEvent {
id: 0,
event_type: UIEventType::EditDraft(f),
});
self.draft = Draft::default();
return true;
}
_ => {}
}
false
@ -191,3 +263,12 @@ impl Component for Composer {
self.pager.set_dirty();
}
}
fn get_display_name(context: &Context, idx: usize) -> String {
let settings = context.accounts[idx].runtime_settings.account();
if let Some(d) = settings.display_name.as_ref() {
format!("{} <{}>", d, settings.identity)
} else {
settings.identity.to_string()
}
}

View File

@ -206,11 +206,11 @@ impl AccountMenu {
cell.set_fg(Color::Byte(243));
x += 1;
continue;
},
}
c if c.is_whitespace() => {
x += 1;
continue;
},
}
_ => {
break;
}

View File

@ -25,6 +25,7 @@ extern crate xdg;
pub mod pager;
use melib::conf::AccountSettings;
use melib::error::*;
use pager::PagerSettings;
use std::collections::HashMap;
@ -34,10 +35,36 @@ pub struct FileAccount {
root_folder: String,
format: String,
sent_folder: String,
identity: String,
display_name: Option<String>,
threaded: bool,
folders: Option<HashMap<String, String>>,
}
impl From<FileAccount> for AccountConf {
fn from(x: FileAccount) -> Self {
let format = x.format.to_lowercase();
let sent_folder = x.sent_folder.clone();
let root_folder = x.root_folder.clone();
let identity = x.identity.clone();
let display_name = x.display_name.clone();
let acc = AccountSettings {
name: String::new(),
root_folder,
format,
sent_folder,
identity,
display_name,
};
AccountConf {
account: acc,
conf: x,
}
}
}
impl FileAccount {
pub fn folders(&self) -> Option<&HashMap<String, String>> {
self.folders.as_ref()
@ -85,45 +112,33 @@ pub struct Settings {
use self::config::{Config, File, FileFormat};
impl FileSettings {
pub fn new() -> FileSettings {
pub fn new() -> Result<FileSettings> {
let xdg_dirs = xdg::BaseDirectories::with_prefix("meli").unwrap();
let config_path = xdg_dirs
.place_config_file("config")
.expect("cannot create configuration directory");
//let setts = Config::default().merge(File::new(config_path.to_str().unwrap_or_default(), config::FileFormat::Toml)).unwrap();
let mut s = Config::new();
let s = s.merge(File::new(config_path.to_str().unwrap(), FileFormat::Toml));
/* No point in returning without a config file.
TODO: Error and exit instead of panic. */
s.unwrap().deserialize().unwrap()
match s.unwrap().deserialize() {
Ok(v) => Ok(v),
Err(e) => Err(MeliError::new(e.to_string())),
}
}
}
impl Settings {
pub fn new() -> Settings {
let fs = FileSettings::new();
let fs = FileSettings::new().unwrap_or_else(|e| panic!(format!("{}", e)));
let mut s: HashMap<String, AccountConf> = HashMap::new();
for (id, x) in fs.accounts {
let format = x.format.to_lowercase();
let sent_folder = x.sent_folder.clone();
let root_folder = x.root_folder.clone();
let mut ac = AccountConf::from(x);
ac.account.set_name(id.clone());
let acc = AccountSettings {
name: id.clone(),
root_folder,
format,
sent_folder,
};
s.insert(
id,
AccountConf {
account: acc,
conf: x,
},
);
s.insert(id, ac);
}
Settings {