ui: add attachments in composer tab
parent
131b4abfbe
commit
d3c658cf00
|
@ -16,7 +16,7 @@ chan-signal = "0.3.1"
|
|||
fnv = "1.0.3" # >:c
|
||||
linkify = "0.3.1" # >:c
|
||||
melib = { path = "../melib", version = "*" }
|
||||
mime_apps = { git = "https://github.com/meli/mime_apps", version = "*" }
|
||||
mime_apps = { git = "https://git.meli.delivery/meli/mime_apps", version = "^0.2.0" }
|
||||
nom = "3.2.0"
|
||||
notify = "4.0.1" # >:c
|
||||
notify-rust = "^3" # >:c
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
use super::*;
|
||||
|
||||
use melib::Draft;
|
||||
use mime_apps::query_mime_info;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
@ -216,37 +217,55 @@ impl Composer {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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,
|
||||
bg_color,
|
||||
((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,
|
||||
)
|
||||
*/
|
||||
fn draw_attachments(&self, grid: &mut CellBuffer, area: Area, _context: &mut Context) {
|
||||
let attachments_no = self.draft.attachments().len();
|
||||
if attachments_no == 0 {
|
||||
write_string_to_grid(
|
||||
"no attachments",
|
||||
grid,
|
||||
Color::Default,
|
||||
Color::Default,
|
||||
(pos_inc(upper_left!(area), (0, 1)), bottom_right!(area)),
|
||||
false,
|
||||
);
|
||||
} else {
|
||||
write_string_to_grid(
|
||||
&format!("{} attachments ", attachments_no),
|
||||
grid,
|
||||
Color::Default,
|
||||
Color::Default,
|
||||
(pos_inc(upper_left!(area), (0, 1)), bottom_right!(area)),
|
||||
false,
|
||||
);
|
||||
for (i, a) in self.draft.attachments().iter().enumerate() {
|
||||
if let Some(name) = a.content_type().name() {
|
||||
write_string_to_grid(
|
||||
&format!(
|
||||
"[{}] \"{}\", {} {} bytes",
|
||||
i,
|
||||
name,
|
||||
a.content_type(),
|
||||
a.raw.len()
|
||||
),
|
||||
grid,
|
||||
Color::Default,
|
||||
Color::Default,
|
||||
(pos_inc(upper_left!(area), (0, 2 + i)), bottom_right!(area)),
|
||||
false,
|
||||
);
|
||||
} else {
|
||||
write_string_to_grid(
|
||||
&format!("[{}] {} {} bytes", i, a.content_type(), a.raw.len()),
|
||||
grid,
|
||||
Color::Default,
|
||||
Color::Default,
|
||||
(pos_inc(upper_left!(area), (0, 2 + i)), bottom_right!(area)),
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Composer {
|
||||
|
@ -257,6 +276,10 @@ impl Component for Composer {
|
|||
|
||||
let upper_left = set_y(upper_left, get_y(upper_left) + 1);
|
||||
|
||||
if height!(area) < 4 {
|
||||
return;
|
||||
}
|
||||
|
||||
let width = if width!(area) > 80 && self.reply_context.is_some() {
|
||||
width!(area) / 2
|
||||
} else {
|
||||
|
@ -275,7 +298,7 @@ impl Component for Composer {
|
|||
self.update_form();
|
||||
self.initialized = true;
|
||||
}
|
||||
let header_height = self.form.len() + 1;
|
||||
let header_height = self.form.len();
|
||||
|
||||
let mid = if width > 80 {
|
||||
let width = width - 80;
|
||||
|
@ -320,29 +343,42 @@ impl Component for Composer {
|
|||
let header_area = if self.reply_context.is_some() {
|
||||
(
|
||||
set_x(upper_left, mid + 1),
|
||||
set_y(bottom_right, get_y(upper_left) + header_height + 1),
|
||||
set_y(bottom_right, get_y(upper_left) + header_height),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
set_x(upper_left, mid + 1),
|
||||
(
|
||||
get_x(bottom_right).saturating_sub(mid),
|
||||
get_y(upper_left) + header_height + 1,
|
||||
get_y(upper_left) + header_height,
|
||||
),
|
||||
)
|
||||
};
|
||||
let body_area = if self.reply_context.is_some() {
|
||||
let attachments_no = self.draft.attachments().len();
|
||||
let attachment_area = if self.reply_context.is_some() {
|
||||
(
|
||||
(mid + 1, get_y(upper_left) + header_height + 1),
|
||||
(mid + 1, get_y(bottom_right) - 2 - attachments_no),
|
||||
bottom_right,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
pos_inc(upper_left, (mid + 1, header_height + 2)),
|
||||
(mid + 1, get_y(bottom_right) - 2 - attachments_no),
|
||||
pos_dec(bottom_right, (mid, 0)),
|
||||
)
|
||||
};
|
||||
|
||||
let body_area = if self.reply_context.is_some() {
|
||||
(
|
||||
(mid + 1, get_y(upper_left) + header_height + 1),
|
||||
set_y(bottom_right, get_y(bottom_right) - 3 - attachments_no),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
pos_inc(upper_left, (mid + 1, header_height + 1)),
|
||||
pos_dec(bottom_right, (mid, 3 + attachments_no)),
|
||||
)
|
||||
};
|
||||
|
||||
let (x, y) = write_string_to_grid(
|
||||
if self.reply_context.is_some() {
|
||||
"COMPOSING REPLY"
|
||||
|
@ -431,6 +467,7 @@ impl Component for Composer {
|
|||
}
|
||||
}
|
||||
|
||||
self.draw_attachments(grid, attachment_area, context);
|
||||
context.dirty_areas.push_back(area);
|
||||
}
|
||||
|
||||
|
@ -587,13 +624,61 @@ impl Component for Composer {
|
|||
return true;
|
||||
}
|
||||
let result = f.read_to_string();
|
||||
self.draft = Draft::from_str(result.as_str()).unwrap();
|
||||
let mut new_draft = Draft::from_str(result.as_str()).unwrap();
|
||||
std::mem::swap(self.draft.attachments_mut(), new_draft.attachments_mut());
|
||||
self.draft = new_draft;
|
||||
self.initialized = false;
|
||||
context.replies.push_back(UIEvent::Fork(ForkType::Finished));
|
||||
context.restore_input();
|
||||
self.dirty = true;
|
||||
return true;
|
||||
}
|
||||
UIEvent::Action(ref a) => {
|
||||
match a {
|
||||
Action::Compose(ComposeAction::AddAttachment(ref path)) => {
|
||||
let mut attachment = match melib::email::attachment_from_file(path) {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
context.replies.push_back(UIEvent::Notification(
|
||||
Some("could not add attachment".to_string()),
|
||||
e.to_string(),
|
||||
));
|
||||
self.dirty = true;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
if let Ok(mime_type) = query_mime_info(path) {
|
||||
match attachment.content_type {
|
||||
ContentType::Other { ref mut tag, .. } => {
|
||||
*tag = mime_type;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
self.draft.attachments_mut().push(attachment);
|
||||
self.dirty = true;
|
||||
return true;
|
||||
}
|
||||
Action::Compose(ComposeAction::RemoveAttachment(idx)) => {
|
||||
if *idx + 1 > self.draft.attachments().len() {
|
||||
context.replies.push_back(UIEvent::StatusEvent(
|
||||
StatusEvent::DisplayMessage(
|
||||
"attachment with given index does not exist".to_string(),
|
||||
),
|
||||
));
|
||||
self.dirty = true;
|
||||
return true;
|
||||
}
|
||||
self.draft.attachments_mut().remove(*idx);
|
||||
context.replies.push_back(UIEvent::StatusEvent(
|
||||
StatusEvent::DisplayMessage("attachment removed".to_string()),
|
||||
));
|
||||
self.dirty = true;
|
||||
return true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
false
|
||||
|
|
|
@ -26,10 +26,12 @@ use nom::{digit, not_line_ending};
|
|||
use std;
|
||||
pub mod actions;
|
||||
pub use crate::actions::Action::{self, *};
|
||||
pub use crate::actions::ComposeAction::{self, *};
|
||||
pub use crate::actions::ListingAction::{self, *};
|
||||
pub use crate::actions::MailingListAction::{self, *};
|
||||
pub use crate::actions::PagerAction::{self, *};
|
||||
pub use crate::actions::TabAction::{self, *};
|
||||
use std::str::FromStr;
|
||||
|
||||
/* Create a const table with every command part that can be auto-completed and its description */
|
||||
macro_rules! define_commands {
|
||||
|
@ -185,6 +187,30 @@ define_commands!([
|
|||
))
|
||||
);
|
||||
)
|
||||
},
|
||||
{ tags: ["add-attachment "],
|
||||
desc: "add-attachment PATH",
|
||||
parser:(
|
||||
named!( add_attachment<Action>,
|
||||
do_parse!(
|
||||
ws!(tag!("add-attachment"))
|
||||
>> path: map_res!(call!(not_line_ending), std::str::from_utf8)
|
||||
>> (Compose(AddAttachment(path.to_string())))
|
||||
)
|
||||
);
|
||||
)
|
||||
},
|
||||
{ tags: ["remove-attachment "],
|
||||
desc: "remove-attachment INDEX",
|
||||
parser:(
|
||||
named!( remove_attachment<Action>,
|
||||
do_parse!(
|
||||
ws!(tag!("remove-attachment"))
|
||||
>> idx: map_res!(map_res!(call!(not_line_ending), std::str::from_utf8), usize::from_str)
|
||||
>> (Compose(RemoveAttachment(idx)))
|
||||
)
|
||||
);
|
||||
)
|
||||
}
|
||||
]);
|
||||
|
||||
|
@ -230,6 +256,12 @@ named!(
|
|||
listing_action<Action>,
|
||||
alt_complete!(toggle | envelope_action | filter | toggle_thread_snooze)
|
||||
);
|
||||
named!(pub parse_command<Action>,
|
||||
alt_complete!( goto | listing_action | sort | subsort | close | mailinglist | setenv | printenv | pipe)
|
||||
|
||||
named!(
|
||||
compose_action<Action>,
|
||||
alt_complete!(add_attachment | remove_attachment)
|
||||
);
|
||||
|
||||
named!(pub parse_command<Action>,
|
||||
alt_complete!( goto | listing_action | sort | subsort | close | mailinglist | setenv | printenv | pipe | compose_action)
|
||||
);
|
||||
|
|
|
@ -64,6 +64,12 @@ pub enum PagerAction {
|
|||
Pipe(String, Vec<String>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ComposeAction {
|
||||
AddAttachment(String),
|
||||
RemoveAttachment(usize),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Action {
|
||||
Listing(ListingAction),
|
||||
|
@ -76,4 +82,5 @@ pub enum Action {
|
|||
Pager(PagerAction),
|
||||
SetEnv(String, String),
|
||||
PrintEnv(String),
|
||||
Compose(ComposeAction),
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue