2018-08-11 15:00:21 +00:00
|
|
|
/*
|
|
|
|
* meli - ui crate
|
|
|
|
*
|
|
|
|
* Copyright 2017-2018 Manos Pitsidianakis
|
|
|
|
*
|
|
|
|
* This file is part of meli.
|
|
|
|
*
|
|
|
|
* meli is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* meli is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
2018-08-29 16:09:51 +00:00
|
|
|
use melib::Draft;
|
2018-09-12 12:10:19 +00:00
|
|
|
use std::str::FromStr;
|
2018-08-29 16:09:51 +00:00
|
|
|
|
2019-02-18 21:14:06 +00:00
|
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
enum Cursor {
|
2019-03-02 06:11:38 +00:00
|
|
|
Headers,
|
2019-02-18 21:14:06 +00:00
|
|
|
Body,
|
2019-03-03 20:11:15 +00:00
|
|
|
//Attachments,
|
2019-02-18 21:14:06 +00:00
|
|
|
}
|
|
|
|
|
2018-08-23 11:39:54 +00:00
|
|
|
#[derive(Debug)]
|
2018-08-16 13:32:47 +00:00
|
|
|
pub struct Composer {
|
2018-09-06 10:05:35 +00:00
|
|
|
reply_context: Option<((usize, usize), Box<ThreadView>)>, // (folder_index, thread_node_index)
|
2018-09-03 22:49:29 +00:00
|
|
|
account_cursor: usize,
|
2018-08-30 12:54:30 +00:00
|
|
|
|
2019-02-18 21:14:06 +00:00
|
|
|
cursor: Cursor,
|
|
|
|
|
2018-09-03 22:49:29 +00:00
|
|
|
pager: Pager,
|
2018-08-29 16:09:51 +00:00
|
|
|
draft: Draft,
|
2019-03-02 06:11:38 +00:00
|
|
|
form: FormWidget,
|
2018-08-30 12:54:30 +00:00
|
|
|
|
2018-09-03 22:49:29 +00:00
|
|
|
mode: ViewMode,
|
2018-08-30 12:54:30 +00:00
|
|
|
dirty: bool,
|
2018-09-03 22:49:29 +00:00
|
|
|
initialized: bool,
|
2018-08-16 13:32:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Composer {
|
|
|
|
fn default() -> Self {
|
|
|
|
Composer {
|
2018-09-03 22:49:29 +00:00
|
|
|
reply_context: None,
|
|
|
|
account_cursor: 0,
|
|
|
|
|
2019-03-02 06:11:38 +00:00
|
|
|
cursor: Cursor::Headers,
|
2019-02-18 21:14:06 +00:00
|
|
|
|
2018-08-30 12:54:30 +00:00
|
|
|
pager: Pager::default(),
|
2018-08-29 16:09:51 +00:00
|
|
|
draft: Draft::default(),
|
2019-03-02 06:11:38 +00:00
|
|
|
form: FormWidget::default(),
|
2018-09-03 22:49:29 +00:00
|
|
|
|
|
|
|
mode: ViewMode::Overview,
|
|
|
|
dirty: true,
|
|
|
|
initialized: false,
|
2018-08-16 13:32:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-23 11:39:54 +00:00
|
|
|
#[derive(Debug)]
|
2018-08-16 13:32:47 +00:00
|
|
|
enum ViewMode {
|
2018-09-03 22:49:29 +00:00
|
|
|
Discard(Uuid),
|
|
|
|
Pager,
|
2019-03-03 20:11:15 +00:00
|
|
|
//Selector(Selector),
|
2018-08-16 13:32:47 +00:00
|
|
|
Overview,
|
|
|
|
}
|
2018-08-11 15:00:21 +00:00
|
|
|
|
2018-09-03 22:49:29 +00:00
|
|
|
impl ViewMode {
|
|
|
|
fn is_discard(&self) -> bool {
|
|
|
|
if let ViewMode::Discard(_) = self {
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_overview(&self) -> bool {
|
|
|
|
if let ViewMode::Overview = self {
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_pager(&self) -> bool {
|
|
|
|
if let ViewMode::Pager = self {
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-11 15:00:21 +00:00
|
|
|
impl fmt::Display for Composer {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
// TODO display subject/info
|
2018-09-03 22:49:29 +00:00
|
|
|
if self.reply_context.is_some() {
|
|
|
|
write!(f, "reply: {:8}", self.draft.headers()["Subject"])
|
|
|
|
} else {
|
|
|
|
write!(f, "compose")
|
|
|
|
}
|
2018-08-11 15:00:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-30 12:54:30 +00:00
|
|
|
impl Composer {
|
2018-09-03 22:49:29 +00:00
|
|
|
/*
|
2018-09-06 10:05:35 +00:00
|
|
|
* coordinates: (account index, mailbox index, root set thread_node index)
|
|
|
|
* msg: index of message we reply to in thread_nodes
|
2018-09-03 22:49:29 +00:00
|
|
|
* context: current context
|
|
|
|
*/
|
|
|
|
pub fn with_context(coordinates: (usize, usize, usize), msg: usize, context: &Context) -> Self {
|
|
|
|
let mailbox = &context.accounts[coordinates.0][coordinates.1]
|
|
|
|
.as_ref()
|
|
|
|
.unwrap();
|
2018-09-06 10:05:35 +00:00
|
|
|
let threads = &mailbox.collection.threads;
|
|
|
|
let thread_nodes = &threads.thread_nodes();
|
2018-09-03 22:49:29 +00:00
|
|
|
let mut ret = Composer::default();
|
2018-09-06 10:05:35 +00:00
|
|
|
let p = &thread_nodes[msg];
|
|
|
|
let parent_message = &mailbox.collection[&p.message().unwrap()];
|
2018-09-04 12:00:23 +00:00
|
|
|
let mut op = context.accounts[coordinates.0]
|
|
|
|
.backend
|
2018-09-23 16:55:29 +00:00
|
|
|
.operation(parent_message.hash(), mailbox.folder.hash());
|
2018-09-04 12:00:23 +00:00
|
|
|
let parent_bytes = op.as_bytes();
|
|
|
|
|
2018-09-12 12:10:19 +00:00
|
|
|
ret.draft = Draft::new_reply(parent_message, parent_bytes.unwrap());
|
2018-09-03 22:49:29 +00:00
|
|
|
ret.draft.headers_mut().insert(
|
|
|
|
"Subject".into(),
|
|
|
|
if p.show_subject() {
|
|
|
|
format!(
|
|
|
|
"Re: {}",
|
2018-09-06 10:05:35 +00:00
|
|
|
mailbox.collection[&p.message().unwrap()].subject().clone()
|
2018-09-03 22:49:29 +00:00
|
|
|
)
|
|
|
|
} else {
|
2018-09-06 10:05:35 +00:00
|
|
|
mailbox.collection[&p.message().unwrap()].subject().into()
|
2018-09-03 22:49:29 +00:00
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
ret.account_cursor = coordinates.0;
|
|
|
|
ret.reply_context = Some((
|
|
|
|
(coordinates.1, coordinates.2),
|
|
|
|
Box::new(ThreadView::new(coordinates, Some(msg), context)),
|
|
|
|
));
|
|
|
|
ret
|
|
|
|
}
|
|
|
|
|
2019-03-02 06:11:38 +00:00
|
|
|
fn update_draft(&mut self) {
|
|
|
|
let header_values = self.form.values_mut();
|
|
|
|
let draft_header_map = self.draft.headers_mut();
|
|
|
|
/* avoid extra allocations by updating values instead of inserting */
|
|
|
|
for (k, v) in draft_header_map.iter_mut() {
|
|
|
|
if let Some(vn) = header_values.remove(k) {
|
|
|
|
std::mem::swap(v, &mut vn.into_string());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn update_form(&mut self) {
|
|
|
|
let old_cursor = self.form.cursor();
|
|
|
|
self.form = FormWidget::new("Save".into());
|
|
|
|
self.form.hide_buttons();
|
|
|
|
self.form.set_cursor(old_cursor);
|
|
|
|
let headers = self.draft.headers();
|
|
|
|
for &k in &["Date", "From", "To", "Cc", "Bcc", "Subject"] {
|
|
|
|
self.form.push((k.into(), headers[k].to_string()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-03 20:11:15 +00:00
|
|
|
/*
|
2019-02-18 21:14:06 +00:00
|
|
|
let (x, y) = if k == "From" {
|
2018-08-30 12:54:30 +00:00
|
|
|
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(
|
2019-02-18 21:14:06 +00:00
|
|
|
&headers[k],
|
2018-08-30 12:54:30 +00:00
|
|
|
grid,
|
|
|
|
Color::Default,
|
2019-02-18 21:14:06 +00:00
|
|
|
bg_color,
|
2018-08-30 12:54:30 +00:00
|
|
|
((x, y), set_y(bottom_right, y)),
|
|
|
|
true,
|
|
|
|
);
|
2019-02-18 21:14:06 +00:00
|
|
|
if k == "From" {
|
2018-08-30 12:54:30 +00:00
|
|
|
write_string_to_grid(
|
|
|
|
" ▶",
|
|
|
|
grid,
|
|
|
|
Color::Byte(251),
|
|
|
|
Color::Default,
|
|
|
|
((x, y), set_y(bottom_right, y)),
|
|
|
|
true,
|
|
|
|
)
|
2019-03-03 20:11:15 +00:00
|
|
|
*/
|
2018-08-30 12:54:30 +00:00
|
|
|
}
|
|
|
|
|
2018-08-11 15:00:21 +00:00
|
|
|
impl Component for Composer {
|
|
|
|
fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
|
2018-09-03 22:49:29 +00:00
|
|
|
if !self.initialized {
|
2018-08-16 13:32:47 +00:00
|
|
|
clear_area(grid, area);
|
2019-03-02 06:11:38 +00:00
|
|
|
self.update_form();
|
2018-09-03 22:49:29 +00:00
|
|
|
self.initialized = true;
|
2018-08-16 13:32:47 +00:00
|
|
|
}
|
2018-09-03 22:49:29 +00:00
|
|
|
|
2018-08-16 13:32:47 +00:00
|
|
|
let upper_left = upper_left!(area);
|
|
|
|
let bottom_right = bottom_right!(area);
|
|
|
|
|
2018-08-29 20:08:23 +00:00
|
|
|
let upper_left = set_y(upper_left, get_y(upper_left) + 1);
|
2019-03-02 06:11:38 +00:00
|
|
|
let header_height = self.form.len() + 1;
|
2018-09-03 22:49:29 +00:00
|
|
|
let width = if width!(area) > 80 && self.reply_context.is_some() {
|
|
|
|
width!(area) / 2
|
|
|
|
} else {
|
|
|
|
width!(area)
|
|
|
|
};
|
|
|
|
|
2018-08-16 13:32:47 +00:00
|
|
|
let mid = if width > 80 {
|
|
|
|
let width = width - 80;
|
2018-09-03 22:49:29 +00:00
|
|
|
let mid = if self.reply_context.is_some() {
|
|
|
|
width!(area) / 2 + width / 2
|
|
|
|
} else {
|
|
|
|
width / 2
|
|
|
|
};
|
|
|
|
|
|
|
|
if self.reply_context.is_some() {
|
|
|
|
for i in get_y(upper_left)..=get_y(bottom_right) {
|
|
|
|
set_and_join_box(grid, (mid, i), VERT_BOUNDARY);
|
|
|
|
grid[(mid, i)].set_fg(Color::Default);
|
|
|
|
grid[(mid, i)].set_bg(Color::Default);
|
|
|
|
}
|
|
|
|
}
|
2018-08-16 13:32:47 +00:00
|
|
|
|
|
|
|
if self.dirty {
|
|
|
|
for i in get_y(upper_left)..=get_y(bottom_right) {
|
2018-08-29 20:08:23 +00:00
|
|
|
//set_and_join_box(grid, (mid, i), VERT_BOUNDARY);
|
2018-08-16 13:32:47 +00:00
|
|
|
grid[(mid, i)].set_fg(Color::Default);
|
|
|
|
grid[(mid, i)].set_bg(Color::Default);
|
2018-08-29 20:08:23 +00:00
|
|
|
//set_and_join_box(grid, (mid + 80, i), VERT_BOUNDARY);
|
2018-08-16 13:32:47 +00:00
|
|
|
grid[(mid + 80, i)].set_fg(Color::Default);
|
|
|
|
grid[(mid + 80, i)].set_bg(Color::Default);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mid
|
2018-08-23 12:36:52 +00:00
|
|
|
} else {
|
|
|
|
0
|
|
|
|
};
|
2018-08-16 13:32:47 +00:00
|
|
|
|
2018-09-03 22:49:29 +00:00
|
|
|
if width > 80 && self.reply_context.is_some() {
|
|
|
|
let area = (upper_left, set_x(bottom_right, mid - 1));
|
|
|
|
let view = &mut self.reply_context.as_mut().unwrap().1;
|
|
|
|
view.draw(grid, area, context);
|
|
|
|
}
|
|
|
|
|
2018-08-16 13:32:47 +00:00
|
|
|
if self.dirty {
|
2018-08-23 12:36:52 +00:00
|
|
|
for i in get_x(upper_left) + mid + 1..=get_x(upper_left) + mid + 79 {
|
2018-08-29 20:08:23 +00:00
|
|
|
//set_and_join_box(grid, (i, header_height), HORZ_BOUNDARY);
|
2018-08-16 13:32:47 +00:00
|
|
|
grid[(i, header_height)].set_fg(Color::Default);
|
|
|
|
grid[(i, header_height)].set_bg(Color::Default);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-30 12:54:30 +00:00
|
|
|
let header_area = (set_x(upper_left, mid + 1), (mid + 78, header_height + 1));
|
2018-08-23 12:36:52 +00:00
|
|
|
let body_area = (
|
|
|
|
(mid + 1, header_height + 2),
|
|
|
|
(mid + 78, get_y(bottom_right)),
|
|
|
|
);
|
2018-08-16 13:32:47 +00:00
|
|
|
|
|
|
|
if self.dirty {
|
2018-09-03 22:49:29 +00:00
|
|
|
self.draft.headers_mut().insert(
|
|
|
|
"From".into(),
|
|
|
|
get_display_name(context, self.account_cursor),
|
|
|
|
);
|
2019-03-02 06:11:38 +00:00
|
|
|
clear_area(grid, body_area);
|
2018-08-16 13:32:47 +00:00
|
|
|
self.dirty = false;
|
|
|
|
}
|
2018-09-03 22:49:29 +00:00
|
|
|
|
|
|
|
/* Regardless of view mode, do the following */
|
|
|
|
clear_area(grid, header_area);
|
2019-03-02 06:11:38 +00:00
|
|
|
/*
|
2018-09-03 22:49:29 +00:00
|
|
|
self.draw_header_table(grid, header_area);
|
2019-03-02 06:11:38 +00:00
|
|
|
*/
|
|
|
|
self.form.draw(grid, header_area, context);
|
2019-02-18 21:14:06 +00:00
|
|
|
|
|
|
|
match self.mode {
|
|
|
|
ViewMode::Overview | ViewMode::Pager => {
|
|
|
|
self.pager.draw(grid, body_area, context);
|
|
|
|
},
|
|
|
|
ViewMode::Discard(_) => {
|
|
|
|
/* Let user choose whether to quit with/without saving or cancel */
|
|
|
|
let mid_x = width!(area) / 2;
|
|
|
|
let mid_y = height!(area) / 2;
|
|
|
|
for x in mid_x - 40..=mid_x + 40 {
|
|
|
|
for y in mid_y - 11..=mid_y + 11 {
|
|
|
|
grid[(x, y)] = Cell::default();
|
|
|
|
}
|
2018-09-04 11:16:01 +00:00
|
|
|
}
|
2018-09-03 22:49:29 +00:00
|
|
|
|
2019-02-18 21:14:06 +00:00
|
|
|
for i in mid_x - 40..=mid_x + 40 {
|
|
|
|
set_and_join_box(grid, (i, mid_y - 11), HORZ_BOUNDARY);
|
2018-09-03 22:49:29 +00:00
|
|
|
|
2019-02-18 21:14:06 +00:00
|
|
|
set_and_join_box(grid, (i, mid_y + 11), HORZ_BOUNDARY);
|
|
|
|
}
|
2018-09-03 22:49:29 +00:00
|
|
|
|
2019-02-18 21:14:06 +00:00
|
|
|
for i in mid_y - 11..=mid_y + 11 {
|
|
|
|
set_and_join_box(grid, (mid_x - 40, i), VERT_BOUNDARY);
|
2018-09-03 22:49:29 +00:00
|
|
|
|
2019-02-18 21:14:06 +00:00
|
|
|
set_and_join_box(grid, (mid_x + 40, i), VERT_BOUNDARY);
|
|
|
|
}
|
2018-09-04 11:16:01 +00:00
|
|
|
|
2019-02-18 21:14:06 +00:00
|
|
|
let area = ((mid_x - 20, mid_y - 7), (mid_x + 39, mid_y + 10));
|
2018-09-04 11:16:01 +00:00
|
|
|
|
2019-02-18 21:14:06 +00:00
|
|
|
let (_, y) = write_string_to_grid(
|
|
|
|
&format!("Draft \"{:10}\"", self.draft.headers()["Subject"]),
|
|
|
|
grid,
|
|
|
|
Color::Default,
|
|
|
|
Color::Default,
|
|
|
|
area,
|
|
|
|
true,
|
|
|
|
);
|
|
|
|
let (_, y) = write_string_to_grid(
|
|
|
|
"[x] quit without saving",
|
|
|
|
grid,
|
|
|
|
Color::Byte(124),
|
|
|
|
Color::Default,
|
|
|
|
(set_y(upper_left!(area), y + 2), bottom_right!(area)),
|
|
|
|
true,
|
|
|
|
);
|
|
|
|
let (_, y) = write_string_to_grid(
|
|
|
|
"[y] save draft and quit",
|
|
|
|
grid,
|
|
|
|
Color::Byte(124),
|
|
|
|
Color::Default,
|
|
|
|
(set_y(upper_left!(area), y + 1), bottom_right!(area)),
|
|
|
|
true,
|
|
|
|
);
|
|
|
|
write_string_to_grid(
|
|
|
|
"[n] cancel",
|
|
|
|
grid,
|
|
|
|
Color::Byte(124),
|
|
|
|
Color::Default,
|
|
|
|
(set_y(upper_left!(area), y + 1), bottom_right!(area)),
|
|
|
|
true,
|
|
|
|
);
|
|
|
|
|
|
|
|
},
|
2018-08-16 13:32:47 +00:00
|
|
|
}
|
2018-09-03 22:49:29 +00:00
|
|
|
|
|
|
|
context.dirty_areas.push_back(area);
|
2018-08-11 15:00:21 +00:00
|
|
|
}
|
|
|
|
|
2019-02-26 15:50:47 +00:00
|
|
|
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
2018-09-03 22:49:29 +00:00
|
|
|
match (&mut self.mode, &mut self.reply_context) {
|
|
|
|
(ViewMode::Pager, _) => {
|
|
|
|
/* Cannot mutably borrow in pattern guard, pah! */
|
|
|
|
if self.pager.process_event(event, context) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(ViewMode::Overview, Some((_, ref mut view))) => {
|
|
|
|
if view.process_event(event, context) {
|
|
|
|
self.dirty = true;
|
|
|
|
return true;
|
|
|
|
}
|
2019-02-18 21:14:06 +00:00
|
|
|
},
|
2018-09-03 22:49:29 +00:00
|
|
|
_ => {}
|
2018-08-23 11:39:54 +00:00
|
|
|
}
|
2019-03-02 06:11:38 +00:00
|
|
|
if self.form.process_event(event, context) {
|
|
|
|
return true;
|
|
|
|
}
|
2018-08-23 11:39:54 +00:00
|
|
|
|
2018-08-16 13:32:47 +00:00
|
|
|
match event.event_type {
|
|
|
|
UIEventType::Resize => {
|
2018-09-04 11:16:01 +00:00
|
|
|
self.set_dirty();
|
2019-02-18 21:14:06 +00:00
|
|
|
},
|
2019-03-02 06:11:38 +00:00
|
|
|
/*
|
2018-09-03 22:49:29 +00:00
|
|
|
/* Switch e-mail From: field to the `left` configured account. */
|
2019-02-18 21:14:06 +00:00
|
|
|
UIEventType::Input(Key::Left) if self.cursor == Cursor::From => {
|
2018-08-30 12:54:30 +00:00
|
|
|
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;
|
|
|
|
}
|
2018-09-03 22:49:29 +00:00
|
|
|
/* Switch e-mail From: field to the `right` configured account. */
|
2019-02-18 21:14:06 +00:00
|
|
|
UIEventType::Input(Key::Right) if self.cursor == Cursor::From => {
|
2018-08-30 12:54:30 +00:00
|
|
|
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;
|
2019-03-02 06:11:38 +00:00
|
|
|
}*/
|
|
|
|
UIEventType::Input(Key::Up) => {
|
|
|
|
self.cursor = Cursor::Headers;
|
|
|
|
},
|
|
|
|
UIEventType::Input(Key::Down) => {
|
|
|
|
self.cursor = Cursor::Body;
|
|
|
|
},
|
2018-09-04 11:16:01 +00:00
|
|
|
UIEventType::Input(Key::Char(key)) if self.mode.is_discard() => {
|
|
|
|
match (key, &self.mode) {
|
|
|
|
('x', ViewMode::Discard(u)) => {
|
2018-09-03 22:49:29 +00:00
|
|
|
context.replies.push_back(UIEvent {
|
|
|
|
id: 0,
|
2018-09-12 12:10:19 +00:00
|
|
|
event_type: UIEventType::Action(Tab(Kill(*u))),
|
2018-09-03 22:49:29 +00:00
|
|
|
});
|
|
|
|
return true;
|
|
|
|
}
|
2019-02-15 17:21:58 +00:00
|
|
|
('n', _) => {},
|
|
|
|
('y', ViewMode::Discard(u)) => {
|
2019-02-16 14:37:14 +00:00
|
|
|
let account = &context.accounts[self.account_cursor];
|
|
|
|
let draft = std::mem::replace(&mut self.draft, Draft::default());
|
|
|
|
eprintln!("{:?}", account.save_draft(draft));
|
|
|
|
|
|
|
|
//eprintln!("{:?}", self.draft.to_string());
|
2019-02-15 17:21:58 +00:00
|
|
|
context.replies.push_back(UIEvent {
|
|
|
|
id: 0,
|
|
|
|
event_type: UIEventType::Action(Tab(Kill(*u))),
|
|
|
|
});
|
|
|
|
return true;
|
|
|
|
},
|
2018-09-03 22:49:29 +00:00
|
|
|
_ => {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.mode = ViewMode::Overview;
|
|
|
|
self.set_dirty();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
/* Switch to Overview mode if we're on Pager mode */
|
|
|
|
UIEventType::Input(Key::Char('o')) if self.mode.is_pager() => {
|
|
|
|
self.mode = ViewMode::Overview;
|
|
|
|
self.set_dirty();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
/* Switch to Pager mode if we're on Overview mode */
|
2018-09-04 12:00:23 +00:00
|
|
|
UIEventType::Input(Key::Char('v')) if self.mode.is_overview() => {
|
2018-09-03 22:49:29 +00:00
|
|
|
self.mode = ViewMode::Pager;
|
|
|
|
self.set_dirty();
|
|
|
|
return true;
|
|
|
|
}
|
2019-03-02 06:11:38 +00:00
|
|
|
UIEventType::Input(Key::Char('e')) if self.cursor == Cursor::Body => {
|
2019-02-18 21:14:06 +00:00
|
|
|
/* Edit draft in $EDITOR */
|
|
|
|
use std::process::{Command, Stdio};
|
|
|
|
/* Kill input thread so that spawned command can be sole receiver of stdin */
|
|
|
|
{
|
|
|
|
context.input_kill();
|
|
|
|
}
|
2019-03-02 06:11:38 +00:00
|
|
|
/* update Draft's headers based on form values */
|
|
|
|
self.update_draft();
|
2019-02-18 21:14:06 +00:00
|
|
|
let mut f =
|
|
|
|
create_temp_file(self.draft.to_string().unwrap().as_str().as_bytes(), None);
|
|
|
|
//let mut f = Box::new(std::fs::File::create(&dir).unwrap());
|
|
|
|
|
|
|
|
// TODO: check exit status
|
|
|
|
Command::new("vim")
|
|
|
|
.arg("+/^$")
|
|
|
|
.arg(&f.path())
|
|
|
|
.stdin(Stdio::inherit())
|
|
|
|
.stdout(Stdio::inherit())
|
|
|
|
.output()
|
|
|
|
.expect("failed to execute process");
|
|
|
|
let result = f.read_to_string();
|
|
|
|
self.draft = Draft::from_str(result.as_str()).unwrap();
|
|
|
|
self.pager.update_from_str(self.draft.body());
|
2019-03-02 06:11:38 +00:00
|
|
|
self.update_form();
|
2019-02-18 21:14:06 +00:00
|
|
|
context.replies.push_back(UIEvent {
|
|
|
|
id: 0,
|
|
|
|
event_type: UIEventType::Fork(ForkType::Finished),
|
|
|
|
});
|
|
|
|
context.restore_input();
|
2019-03-02 06:11:38 +00:00
|
|
|
/*
|
|
|
|
|
2019-02-18 21:14:06 +00:00
|
|
|
Cursor::To | Cursor::Cc | Cursor::Bcc => {
|
|
|
|
let account = &context.accounts[self.account_cursor];
|
2019-02-21 13:44:26 +00:00
|
|
|
let mut entries = account.address_book.values().map(|v| (v.id().as_bytes().to_vec(), v.email().to_string())).collect();
|
2019-02-18 21:14:06 +00:00
|
|
|
self.mode = ViewMode::Selector(Selector::new(entries, true));
|
|
|
|
},
|
|
|
|
Cursor::Attachments => {
|
|
|
|
unimplemented!()
|
|
|
|
},
|
|
|
|
Cursor::From => {
|
|
|
|
return true;
|
|
|
|
}
|
2019-03-02 06:11:38 +00:00
|
|
|
*/
|
2018-08-16 13:32:47 +00:00
|
|
|
self.dirty = true;
|
2018-08-23 11:39:54 +00:00
|
|
|
return true;
|
2018-08-23 12:36:52 +00:00
|
|
|
}
|
|
|
|
_ => {}
|
2018-08-16 13:32:47 +00:00
|
|
|
}
|
2018-08-23 11:39:54 +00:00
|
|
|
false
|
2018-08-16 13:32:47 +00:00
|
|
|
}
|
2018-08-11 15:00:21 +00:00
|
|
|
|
|
|
|
fn is_dirty(&self) -> bool {
|
2018-09-23 16:55:29 +00:00
|
|
|
self.dirty || self.pager.is_dirty() || self
|
|
|
|
.reply_context
|
|
|
|
.as_ref()
|
|
|
|
.map(|(_, p)| p.is_dirty())
|
2019-03-02 06:11:38 +00:00
|
|
|
.unwrap_or(false) || self.form.is_dirty()
|
2018-08-16 13:32:47 +00:00
|
|
|
}
|
2018-08-24 23:23:40 +00:00
|
|
|
|
2018-08-16 13:32:47 +00:00
|
|
|
fn set_dirty(&mut self) {
|
|
|
|
self.dirty = true;
|
|
|
|
self.pager.set_dirty();
|
2019-03-02 06:11:38 +00:00
|
|
|
self.form.set_dirty();
|
2018-09-03 22:49:29 +00:00
|
|
|
if let Some((_, ref mut view)) = self.reply_context {
|
|
|
|
view.set_dirty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn kill(&mut self, uuid: Uuid) {
|
|
|
|
self.mode = ViewMode::Discard(uuid);
|
2018-08-11 15:00:21 +00:00
|
|
|
}
|
|
|
|
}
|
2018-08-30 12:54:30 +00:00
|
|
|
|
|
|
|
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()
|
|
|
|
}
|
|
|
|
}
|