Add edit envelope action back as async

memfd
Manos Pitsidianakis 2020-08-25 15:39:43 +03:00
parent f7c9f21575
commit 53e924eb33
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
8 changed files with 96 additions and 61 deletions

View File

@ -24,9 +24,7 @@
*/
use crate::components::Component;
use melib::backends::AccountHash;
pub use melib::thread::{SortField, SortOrder};
use melib::{Draft, EnvelopeHash};
extern crate uuid;
use uuid::Uuid;
@ -58,11 +56,9 @@ pub enum ListingAction {
#[derive(Debug)]
pub enum TabAction {
New(Option<Box<dyn Component>>),
NewDraft(AccountHash, Option<Draft>),
Close,
Edit(AccountHash, EnvelopeHash), // account_position, envelope hash
Kill(Uuid),
New(Option<Box<dyn Component>>),
}
#[derive(Debug)]

View File

@ -642,9 +642,11 @@ impl Component for ContactList {
let mut draft: Draft = Draft::default();
*draft.headers_mut().get_mut("To").unwrap() =
format!("{} <{}>", &card.name(), &card.email());
let mut composer = Composer::new(account_hash, context);
composer.set_draft(draft);
context
.replies
.push_back(UIEvent::Action(Tab(NewDraft(account_hash, Some(draft)))));
.push_back(UIEvent::Action(Tab(New(Some(Box::new(composer))))));
return true;
}

View File

@ -286,6 +286,7 @@ pub trait MailListingTrait: ListingTrait {
name: "message copying".into(),
handle,
channel,
on_finish: None,
},
);
}
@ -323,6 +324,7 @@ pub trait MailListingTrait: ListingTrait {
name: "message moving".into(),
handle,
channel,
on_finish: None,
},
);
}
@ -1099,9 +1101,10 @@ impl Component for Listing {
if shortcut!(k == shortcuts[Listing::DESCRIPTION]["new_mail"]) =>
{
let account_hash = context.accounts[self.cursor_pos.0].hash();
let composer = Composer::new(account_hash, context);
context
.replies
.push_back(UIEvent::Action(Tab(NewDraft(account_hash, None))));
.push_back(UIEvent::Action(Tab(New(Some(Box::new(composer))))));
return true;
}
UIEvent::StartupCheck(_) => {

View File

@ -1137,10 +1137,66 @@ impl Component for MailView {
UIEvent::Input(ref key)
if shortcut!(key == shortcuts[MailView::DESCRIPTION]["edit"]) =>
{
context.replies.push_back(UIEvent::Action(Tab(Edit(
self.coordinates.0,
self.coordinates.2,
))));
let account_hash = self.coordinates.0;
let env_hash = self.coordinates.2;
let (sender, mut receiver) = crate::jobs::oneshot::channel();
let operation = context.accounts[&account_hash].operation(env_hash);
let bytes_job = async move {
let _ = sender.send(operation?.as_bytes()?.await);
Ok(())
};
let (channel, handle, job_id) = if context.accounts[&account_hash]
.backend_capabilities
.is_async
{
context.accounts[&account_hash]
.job_executor
.spawn_specialized(bytes_job)
} else {
context.accounts[&account_hash]
.job_executor
.spawn_blocking(bytes_job)
};
context.accounts[&account_hash].insert_job(
job_id,
crate::conf::accounts::JobRequest::Generic {
name: "fetch envelope".into(),
handle,
channel,
on_finish: Some(CallbackFn(Box::new(move |context: &mut Context| {
let result = receiver.try_recv().unwrap().unwrap();
match result.and_then(|bytes| {
Composer::edit(account_hash, env_hash, &bytes, context)
}) {
Ok(composer) => {
context.replies.push_back(UIEvent::Action(Tab(New(Some(
Box::new(composer),
)))));
}
Err(err) => {
let err_string = format!(
"Failed to open envelope {}: {}",
context.accounts[&account_hash]
.collection
.envelopes
.read()
.unwrap()
.get(&env_hash)
.map(|env| env.message_id_display())
.unwrap_or_else(|| "Not found".into()),
err.to_string()
);
log(&err_string, ERROR);
context.replies.push_back(UIEvent::Notification(
Some("Failed to open e-mail".to_string()),
err_string,
Some(NotificationType::ERROR),
));
}
}
}))),
},
);
return true;
}
UIEvent::Input(ref key)
@ -1538,10 +1594,11 @@ impl Component for MailView {
{
if let Ok(mailto) = Mailto::try_from(list_post_addr) {
let draft: Draft = mailto.into();
context.replies.push_back(UIEvent::Action(Tab(NewDraft(
self.coordinates.0,
Some(draft),
))));
let mut composer = Composer::new(self.coordinates.0, context);
composer.set_draft(draft);
context.replies.push_back(UIEvent::Action(Tab(New(Some(
Box::new(composer),
)))));
failure = false;
}
}

View File

@ -1662,52 +1662,6 @@ impl Component for Tabbed {
self.dirty = true;
return true;
}
UIEvent::Action(Tab(NewDraft(account_hash, ref draft))) => {
let mut composer = Composer::new(*account_hash, context);
if let Some(draft) = draft {
composer.set_draft(draft.clone());
}
self.add_component(Box::new(composer));
self.cursor_pos = self.children.len() - 1;
self.children[self.cursor_pos].set_dirty(true);
let mut children_maps = self.children[self.cursor_pos].get_shortcuts(context);
children_maps.extend(self.get_shortcuts(context));
self.help_curr_views = children_maps;
return true;
}
UIEvent::Action(Tab(Edit(_, _))) => {
/* FIXME
let composer = match Composer::edit(*account_hash, *msg, context) {
Ok(c) => c,
Err(e) => {
context.replies.push_back(UIEvent::Notification(
Some("Failed to open e-mail".to_string()),
e.to_string(),
Some(NotificationType::ERROR),
));
log(
format!(
"Failed to open envelope {}: {}",
context.accounts[&*account_hash]
.collection
.get_env(*msg)
.message_id_display(),
e.to_string()
),
ERROR,
);
return true;
}
};
self.add_component(Box::new(composer));
self.cursor_pos = self.children.len() - 1;
self.children[self.cursor_pos].set_dirty(true);
let mut children_maps = self.children[self.cursor_pos].get_shortcuts(context);
children_maps.extend(self.get_shortcuts(context));
self.help_curr_views = children_maps;
*/
return true;
}
UIEvent::Action(Tab(New(ref mut e))) if e.is_some() => {
self.add_component(e.take().unwrap());
self.cursor_pos = self.children.len() - 1;

View File

@ -176,6 +176,7 @@ pub enum JobRequest {
name: Cow<'static, str>,
handle: JoinHandle,
channel: JobChannel<()>,
on_finish: Option<crate::types::CallbackFn>,
},
IsOnline(JoinHandle, oneshot::Receiver<Result<()>>),
Refresh(MailboxHash, JoinHandle, oneshot::Receiver<Result<()>>),
@ -1796,6 +1797,7 @@ impl Account {
ref name,
ref mut channel,
handle: _,
ref mut on_finish,
} => {
let r = channel.try_recv().unwrap();
match r {
@ -1819,6 +1821,13 @@ impl Account {
}
None => {}
}
if on_finish.is_some() {
self.sender
.send(ThreadEvent::UIEvent(UIEvent::Callback(
on_finish.take().unwrap(),
)))
.unwrap();
}
self.sender
.send(ThreadEvent::UIEvent(UIEvent::StatusEvent(
StatusEvent::JobFinished(*job_id),

View File

@ -888,6 +888,7 @@ impl State {
name: "Message index rebuild".into(),
handle,
channel,
on_finish: None,
},
);
self.context.replies.push_back(UIEvent::Notification(
@ -1089,6 +1090,10 @@ impl State {
return;
}
}
UIEvent::Callback(callback_fn) => {
(callback_fn.0)(&mut self.context);
return;
}
UIEvent::GlobalUIDialog(dialog) => {
self.overlay.push(dialog);
return;

View File

@ -126,10 +126,19 @@ pub enum UIEvent {
Contacts(ContactEvent),
Compose(ComposeEvent),
FinishedUIDialog(ComponentId, UIMessage),
Callback(CallbackFn),
GlobalUIDialog(Box<dyn Component>),
Timer(u8),
}
pub struct CallbackFn(pub Box<dyn FnOnce(&mut crate::Context) -> () + Send + 'static>);
impl core::fmt::Debug for CallbackFn {
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(fmt, "CallbackFn")
}
}
impl From<RefreshEvent> for UIEvent {
fn from(event: RefreshEvent) -> Self {
UIEvent::RefreshEvent(Box::new(event))