crumb = new HashMap<>();
crumb.put("draft", Long.toString(id));
crumb.put("reference", Long.toString(reference));
crumb.put("action", action);
Log.breadcrumb("compose", crumb);
DraftData data = new DraftData();
DB db = DB.getInstance(context);
try {
db.beginTransaction();
data.identities = db.identity().getComposableIdentities(null);
if (data.identities == null || data.identities.size() == 0)
throw new IllegalStateException(getString(R.string.title_no_identities));
data.draft = db.message().getMessage(id);
if (data.draft == null || data.draft.ui_hide) {
// New draft
if ("edit".equals(action))
throw new MessageRemovedException("Draft for edit was deleted hide=" + (data.draft != null));
EntityMessage ref = db.message().getMessage(reference);
String body = "";
data.draft = new EntityMessage();
data.draft.msgid = EntityMessage.generateMessageId();
if (plain_only)
data.draft.plain_only = true;
if (encrypt_default)
data.draft.encrypt = true;
if (receipt_default)
data.draft.receipt_request = true;
if (ref == null) {
data.draft.thread = data.draft.msgid;
try {
String to = args.getString("to");
data.draft.to = (TextUtils.isEmpty(to) ? null : InternetAddress.parse(to));
} catch (AddressException ex) {
Log.w(ex);
}
try {
String cc = args.getString("cc");
data.draft.cc = (TextUtils.isEmpty(cc) ? null : InternetAddress.parse(cc));
} catch (AddressException ex) {
Log.w(ex);
}
try {
String bcc = args.getString("bcc");
data.draft.bcc = (TextUtils.isEmpty(bcc) ? null : InternetAddress.parse(bcc));
} catch (AddressException ex) {
Log.w(ex);
}
data.draft.subject = args.getString("subject", "");
body = args.getString("body", "");
if (!TextUtils.isEmpty(body))
body = HtmlHelper.sanitize(context, body, false);
if (answer > 0) {
EntityAnswer a = db.answer().getAnswer(answer);
if (a != null) {
data.draft.subject = a.name;
body = a.getText(null) + body;
}
}
} else {
// Actions:
// - reply
// - reply_all
// - forward
// - editasnew
// - list
// - receipt
// - participation
if ("reply".equals(action) || "reply_all".equals(action) ||
"list".equals(action) ||
"receipt".equals(action) ||
"participation".equals(action)) {
data.draft.references = (ref.references == null ? "" : ref.references + " ") + ref.msgid;
data.draft.inreplyto = ref.msgid;
data.draft.thread = ref.thread;
if ("list".equals(action) && ref.list_post != null)
data.draft.to = ref.list_post;
else if ("receipt".equals(action) && ref.receipt_to != null)
data.draft.to = ref.receipt_to;
else {
// Prevent replying to self
if (ref.replySelf(data.identities, ref.account)) {
data.draft.from = ref.from;
data.draft.to = ref.to;
} else {
data.draft.from = ref.to;
data.draft.to = (ref.reply == null || ref.reply.length == 0 ? ref.from : ref.reply);
}
if (data.draft.from != null && data.draft.from.length > 0) {
String from = ((InternetAddress) data.draft.from[0]).getAddress();
if (from != null && from.contains("@"))
data.draft.extra = from.substring(0, from.indexOf("@"));
}
}
if ("reply_all".equals(action))
data.draft.cc = ref.getAllRecipients(data.identities, ref.account);
else if ("receipt".equals(action)) {
data.draft.receipt = true;
data.draft.receipt_request = false;
}
} else if ("forward".equals(action) || "editasnew".equals(action))
data.draft.thread = data.draft.msgid; // new thread
String subject = (ref.subject == null ? "" : ref.subject);
if ("reply".equals(action) || "reply_all".equals(action)) {
if (prefix_once) {
String re = context.getString(R.string.title_subject_reply, "");
subject = unprefix(subject, re);
}
data.draft.subject = context.getString(R.string.title_subject_reply, subject);
} else if ("forward".equals(action)) {
if (prefix_once) {
String fwd = context.getString(R.string.title_subject_forward, "");
subject = unprefix(subject, fwd);
}
data.draft.subject = context.getString(R.string.title_subject_forward, subject);
} else if ("editasnew".equals(action)) {
data.draft.subject = ref.subject;
if (ref.content) {
String html = Helper.readText(ref.getFile(context));
body = HtmlHelper.sanitize(context, html, true);
}
} else if ("list".equals(action)) {
data.draft.subject = ref.subject;
} else if ("receipt".equals(action)) {
data.draft.subject = context.getString(R.string.title_receipt_subject, subject);
Configuration configuration = new Configuration(context.getResources().getConfiguration());
configuration.setLocale(new Locale("en"));
Resources res = context.createConfigurationContext(configuration).getResources();
body = "" + context.getString(R.string.title_receipt_text) + "
";
if (!Locale.getDefault().getLanguage().equals("en"))
body += "" + res.getString(R.string.title_receipt_text) + "
";
} else if ("participation".equals(action))
data.draft.subject = status + ": " + ref.subject;
if (ref.plain_only != null && ref.plain_only)
data.draft.plain_only = ref.plain_only;
if (answer > 0) {
EntityAnswer a = db.answer().getAnswer(answer);
if (a != null)
body = a.getText(data.draft.to) + body;
}
}
// Select identity matching from address
EntityIdentity selected = null;
long aid = args.getLong("account", -1);
long iid = args.getLong("identity", -1);
if (aid < 0 && ref != null)
aid = ref.account;
if (iid < 0 && ref != null && ref.identity != null)
iid = ref.identity;
if (iid >= 0)
for (EntityIdentity identity : data.identities)
if (identity.id.equals(iid)) {
Log.i("Selected requested identity=" + iid);
selected = identity;
break;
}
if (data.draft.from != null && data.draft.from.length > 0) {
if (selected == null)
for (Address sender : data.draft.from)
for (EntityIdentity identity : data.identities)
if (identity.account.equals(aid) &&
identity.sameAddress(sender)) {
selected = identity;
Log.i("Selected same account/identity");
break;
}
if (selected == null)
for (Address sender : data.draft.from)
for (EntityIdentity identity : data.identities)
if (identity.account.equals(aid) &&
identity.similarAddress(sender)) {
selected = identity;
Log.i("Selected similar account/identity");
break;
}
if (selected == null)
for (Address sender : data.draft.from)
for (EntityIdentity identity : data.identities)
if (identity.sameAddress(sender)) {
selected = identity;
Log.i("Selected same */identity");
break;
}
if (selected == null)
for (Address sender : data.draft.from)
for (EntityIdentity identity : data.identities)
if (identity.similarAddress(sender)) {
selected = identity;
Log.i("Selected similer */identity");
break;
}
}
if (selected == null)
for (EntityIdentity identity : data.identities)
if (identity.account.equals(aid) && identity.primary) {
selected = identity;
Log.i("Selected primary account/identity");
break;
}
if (selected == null)
for (EntityIdentity identity : data.identities)
if (identity.account.equals(aid)) {
selected = identity;
Log.i("Selected account/identity");
break;
}
if (selected == null)
for (EntityIdentity identity : data.identities)
if (identity.primary) {
Log.i("Selected primary */identity");
selected = identity;
break;
}
if (selected == null)
for (EntityIdentity identity : data.identities) {
Log.i("Selected */identity");
selected = identity;
break;
}
if (selected == null)
throw new IllegalArgumentException(context.getString(R.string.title_no_identities));
EntityFolder drafts = db.folder().getFolderByType(selected.account, EntityFolder.DRAFTS);
if (drafts == null)
throw new IllegalArgumentException(context.getString(R.string.title_no_primary_drafts));
data.draft.account = drafts.account;
data.draft.folder = drafts.id;
data.draft.identity = selected.id;
data.draft.from = new InternetAddress[]{new InternetAddress(selected.email, selected.name)};
data.draft.sender = MessageHelper.getSortKey(data.draft.from);
Uri lookupUri = ContactInfo.getLookupUri(context, data.draft.from);
data.draft.avatar = (lookupUri == null ? null : lookupUri.toString());
data.draft.received = new Date().getTime();
data.draft.seen = true;
data.draft.ui_seen = true;
data.draft.id = db.message().insertMessage(data.draft);
Helper.writeText(data.draft.getFile(context), body);
db.message().setMessageContent(data.draft.id,
true,
data.draft.plain_only,
HtmlHelper.getPreview(body),
null);
if ("participation".equals(action)) {
EntityAttachment attachment = new EntityAttachment();
attachment.message = data.draft.id;
attachment.sequence = 1;
attachment.name = "meeting.ics";
attachment.type = "text/calendar";
attachment.disposition = Part.ATTACHMENT;
attachment.size = ics.length();
attachment.progress = null;
attachment.available = true;
attachment.id = db.attachment().insertAttachment(attachment);
ics.renameTo(attachment.getFile(context));
}
// Write reference text
if (ref != null && ref.content &&
!"editasnew".equals(action) &&
!"list".equals(action) &&
!"receipt".equals(action)) {
String refText = Helper.readText(ref.getFile(context));
boolean usenet = prefs.getBoolean("usenet_signature", false);
if (usenet) {
Document rdoc = JsoupEx.parse(refText);
List tbd = new ArrayList<>();
NodeTraversor.traverse(new NodeVisitor() {
boolean found = false;
public void head(Node node, int depth) {
if (node instanceof TextNode &&
"-- ".equals(((TextNode) node).getWholeText()) &&
node.nextSibling() != null &&
"br".equals(node.nextSibling().nodeName()))
found = true;
if (found)
tbd.add(node);
}
public void tail(Node node, int depth) {
// Do nothing
}
}, rdoc);
if (tbd.size() > 0) {
for (Node node : tbd)
node.remove();
refText = (rdoc.body() == null ? "" : rdoc.body().html());
}
}
if ("reply".equals(action) || "reply_all".equals(action))
refText = "" + refText + "
";
String refBody = String.format("%s %s:
\n%s",
Html.escapeHtml(new Date(ref.received).toString()),
Html.escapeHtml(MessageHelper.formatAddresses(ref.from)),
refText);
Helper.writeText(data.draft.getRefFile(context), refBody);
}
if ("new".equals(action)) {
ArrayList uris = args.getParcelableArrayList("attachments");
if (uris != null)
for (Uri uri : uris)
try {
addAttachment(context, data.draft.id, uri, false);
} catch (IOException ex) {
Log.e(ex);
}
} else if (ref != null &&
("reply".equals(action) || "reply_all".equals(action) ||
"forward".equals(action) || "editasnew".equals(action))) {
int sequence = 0;
List attachments = db.attachment().getAttachments(ref.id);
for (EntityAttachment attachment : attachments)
if (attachment.encryption != null &&
attachment.encryption.equals(EntityAttachment.PGP_MESSAGE)) {
data.draft.encrypt = true;
db.message().setMessageEncrypt(data.draft.id, true);
} else if (attachment.encryption == null &&
("forward".equals(action) || "editasnew".equals(action) ||
(attachment.isInline() && attachment.isImage()))) {
if (attachment.available) {
File source = attachment.getFile(context);
attachment.id = null;
attachment.message = data.draft.id;
attachment.sequence = ++sequence;
attachment.id = db.attachment().insertAttachment(attachment);
File target = attachment.getFile(context);
Helper.copy(source, target);
if (!"forward".equals(action))
resizeAttachment(context, attachment);
} else
args.putBoolean("incomplete", true);
}
}
if (data.draft.encrypt == null || !data.draft.encrypt)
EntityOperation.queue(context, data.draft, EntityOperation.ADD);
} else {
if (data.draft.content) {
File file = data.draft.getFile(context);
String html = Helper.readText(file);
html = HtmlHelper.sanitize(context, html, true);
Helper.writeText(file, html);
} else {
if (data.draft.uid == null)
throw new IllegalStateException("Draft without uid");
EntityOperation.queue(context, data.draft, EntityOperation.BODY);
}
List attachments = db.attachment().getAttachments(data.draft.id);
for (EntityAttachment attachment : attachments)
if (!attachment.available)
EntityOperation.queue(context, data.draft, EntityOperation.ATTACHMENT, attachment.id);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
return data;
}
@Override
protected void onExecuted(Bundle args, final DraftData data) {
final String action = getArguments().getString("action");
Log.i("Loaded draft id=" + data.draft.id + " action=" + action);
working = data.draft.id;
encrypt = (data.draft.encrypt != null && data.draft.encrypt);
getActivity().invalidateOptionsMenu();
// Show identities
AdapterIdentitySelect iadapter = new AdapterIdentitySelect(getContext(), data.identities);
spIdentity.setAdapter(iadapter);
// Select identity
if (data.draft.identity != null)
for (int pos = 0; pos < data.identities.size(); pos++) {
if (data.identities.get(pos).id.equals(data.draft.identity)) {
spIdentity.setSelection(pos);
break;
}
}
etExtra.setText(data.draft.extra);
etTo.setText(MessageHelper.formatAddressesCompose(data.draft.to));
etCc.setText(MessageHelper.formatAddressesCompose(data.draft.cc));
etBcc.setText(MessageHelper.formatAddressesCompose(data.draft.bcc));
etSubject.setText(data.draft.subject);
long reference = args.getLong("reference", -1);
etTo.setTag(reference < 0 ? "" : etTo.getText().toString());
etSubject.setTag(reference < 0 ? "" : etSubject.getText().toString());
grpHeader.setVisibility(View.VISIBLE);
grpAddresses.setVisibility("reply_all".equals(action) ? View.VISIBLE : View.GONE);
ibCcBcc.setVisibility(View.VISIBLE);
bottom_navigation.getMenu().findItem(R.id.action_undo).setVisible(
data.draft.revision != null && data.draft.revision > 1);
bottom_navigation.getMenu().findItem(R.id.action_redo).setVisible(
data.draft.revision != null && !data.draft.revision.equals(data.draft.revisions));
if (args.getBoolean("incomplete"))
Snackbar.make(view, R.string.title_attachments_incomplete, Snackbar.LENGTH_LONG).show();
DB db = DB.getInstance(getContext());
db.attachment().liveAttachments(data.draft.id).observe(getViewLifecycleOwner(),
new Observer>() {
private int last_available = 0;
@Override
public void onChanged(@Nullable List attachments) {
if (attachments == null)
attachments = new ArrayList<>();
adapter.set(attachments);
grpAttachments.setVisibility(attachments.size() > 0 ? View.VISIBLE : View.GONE);
int available = 0;
boolean downloading = false;
boolean inline_images = false;
for (EntityAttachment attachment : attachments) {
if (attachment.available)
available++;
if (attachment.progress != null)
downloading = true;
if (attachment.isInline() && attachment.isImage())
inline_images = true;
}
Log.i("Attachments=" + attachments.size() +
" available=" + available + " downloading=" + downloading);
// Attachment deleted: update remote draft
if (available < last_available)
onAction(R.id.action_save);
last_available = available;
rvAttachment.setTag(downloading);
checkInternet();
tvUnusedInlineImages.setVisibility(inline_images ? View.VISIBLE : View.GONE);
}
});
db.message().liveMessage(data.draft.id).observe(getViewLifecycleOwner(), new Observer() {
@Override
public void onChanged(EntityMessage draft) {
// Draft was deleted
if (draft == null || draft.ui_hide)
finish();
else {
encrypt = (draft.encrypt != null && draft.encrypt);
getActivity().invalidateOptionsMenu();
Log.i("Draft content=" + draft.content);
if (draft.content && state == State.NONE)
showDraft(draft);
tvNoInternet.setTag(draft.content);
checkInternet();
}
}
});
}
@Override
protected void onException(Bundle args, Throwable ex) {
pbWait.setVisibility(View.GONE);
// External app sending absolute file
if (ex instanceof MessageRemovedException)
finish();
else if (ex instanceof SecurityException)
handleFileShare();
else if (ex instanceof IllegalArgumentException)
Snackbar.make(view, ex.getMessage(), Snackbar.LENGTH_LONG).show();
else if (ex instanceof IllegalStateException) {
Snackbar snackbar = Snackbar.make(view, ex.getMessage(), Snackbar.LENGTH_INDEFINITE);
snackbar.setAction(R.string.title_fix, new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(getContext(), ActivitySetup.class));
getActivity().finish();
}
});
snackbar.show();
} else
Helper.unexpectedError(getParentFragmentManager(), ex);
}
};
private void handleFileShare() {
Snackbar sb = Snackbar.make(view, R.string.title_no_stream, Snackbar.LENGTH_INDEFINITE);
sb.setAction(R.string.title_info, new View.OnClickListener() {
@Override
public void onClick(View v) {
Helper.viewFAQ(getContext(), 49);
}
});
sb.show();
}
private SimpleTask actionLoader = new SimpleTask() {
int last_available = 0;
@Override
protected void onPreExecute(Bundle args) {
setBusy(true);
}
@Override
protected void onPostExecute(Bundle args) {
int action = args.getInt("action");
if (action != R.id.action_check)
setBusy(false);
}
@Override
protected EntityMessage onExecute(final Context context, Bundle args) throws Throwable {
// Get data
long id = args.getLong("id");
int action = args.getInt("action");
long aid = args.getLong("account");
long iid = args.getLong("identity");
String extra = args.getString("extra");
String to = args.getString("to");
String cc = args.getString("cc");
String bcc = args.getString("bcc");
String subject = args.getString("subject");
String body = args.getString("body");
boolean empty = args.getBoolean("empty");
EntityMessage draft;
DB db = DB.getInstance(context);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
try {
db.beginTransaction();
// Get draft & selected identity
draft = db.message().getMessage(id);
EntityIdentity identity = db.identity().getIdentity(iid);
// Draft deleted by server
if (draft == null || draft.ui_hide)
throw new MessageRemovedException("Draft for action was deleted hide=" + (draft != null));
Log.i("Load action id=" + draft.id + " action=" + getActionName(action));
if (action == R.id.action_delete) {
boolean discard_delete = prefs.getBoolean("discard_delete", false);
EntityFolder trash = db.folder().getFolderByType(draft.account, EntityFolder.TRASH);
if (empty || trash == null || discard_delete)
EntityOperation.queue(context, draft, EntityOperation.DELETE);
else
EntityOperation.queue(context, draft, EntityOperation.MOVE, trash.id);
if (!empty) {
Handler handler = new Handler(context.getMainLooper());
handler.post(new Runnable() {
public void run() {
ToastEx.makeText(context, R.string.title_draft_deleted, Toast.LENGTH_LONG).show();
}
});
}
} else {
// Move draft to new account
if (draft.account != aid && aid >= 0) {
Log.i("Account changed");
Long uid = draft.uid;
String msgid = draft.msgid;
boolean content = draft.content;
Boolean ui_hide = draft.ui_hide;
// To prevent violating constraints
draft.uid = null;
draft.msgid = null;
db.message().updateMessage(draft);
// Create copy to delete
draft.id = null;
draft.uid = uid;
draft.msgid = msgid;
draft.content = false;
draft.ui_hide = true;
draft.id = db.message().insertMessage(draft);
EntityOperation.queue(context, draft, EntityOperation.DELETE);
// Restore original with new account, no uid and new msgid
draft.id = id;
draft.account = aid;
draft.folder = db.folder().getFolderByType(aid, EntityFolder.DRAFTS).id;
draft.uid = null;
draft.msgid = EntityMessage.generateMessageId();
draft.content = content;
draft.ui_hide = ui_hide;
db.message().updateMessage(draft);
if (draft.content && (draft.encrypt == null || !draft.encrypt))
EntityOperation.queue(context, draft, EntityOperation.ADD);
}
Map crumb = new HashMap<>();
crumb.put("draft", draft.folder + ":" + draft.id);
crumb.put("content", Boolean.toString(draft.content));
crumb.put("file", Boolean.toString(draft.getFile(context).exists()));
crumb.put("action", getActionName(action));
Log.breadcrumb("compose", crumb);
List attachments = db.attachment().getAttachments(draft.id);
// Get data
InternetAddress afrom[] = (identity == null ? null : new InternetAddress[]{new InternetAddress(identity.email, identity.name)});
InternetAddress ato[] = null;
InternetAddress acc[] = null;
InternetAddress abcc[] = null;
boolean lookup_mx = prefs.getBoolean("lookup_mx", false);
if (!TextUtils.isEmpty(to))
try {
ato = InternetAddress.parse(to);
if (action == R.id.action_send) {
for (InternetAddress address : ato)
address.validate();
if (lookup_mx)
ConnectionHelper.lookupMx(ato, context);
}
} catch (AddressException ex) {
throw new AddressException(context.getString(R.string.title_address_parse_error,
Helper.ellipsize(to, ADDRESS_ELLIPSIZE), ex.getMessage()));
}
if (!TextUtils.isEmpty(cc))
try {
acc = InternetAddress.parse(cc);
if (action == R.id.action_send) {
for (InternetAddress address : acc)
address.validate();
if (lookup_mx)
ConnectionHelper.lookupMx(acc, context);
}
} catch (AddressException ex) {
throw new AddressException(context.getString(R.string.title_address_parse_error,
Helper.ellipsize(cc, ADDRESS_ELLIPSIZE), ex.getMessage()));
}
if (!TextUtils.isEmpty(bcc))
try {
abcc = InternetAddress.parse(bcc);
if (action == R.id.action_send) {
for (InternetAddress address : abcc)
address.validate();
if (lookup_mx)
ConnectionHelper.lookupMx(abcc, context);
}
} catch (AddressException ex) {
throw new AddressException(context.getString(R.string.title_address_parse_error,
Helper.ellipsize(bcc, ADDRESS_ELLIPSIZE), ex.getMessage()));
}
if (TextUtils.isEmpty(extra))
extra = null;
int available = 0;
for (EntityAttachment attachment : attachments)
if (attachment.available)
available++;
Long ident = (identity == null ? null : identity.id);
boolean dirty = (!Objects.equals(draft.identity, ident) ||
!Objects.equals(draft.extra, extra) ||
!MessageHelper.equal(draft.from, afrom) ||
!MessageHelper.equal(draft.to, ato) ||
!MessageHelper.equal(draft.cc, acc) ||
!MessageHelper.equal(draft.bcc, abcc) ||
!Objects.equals(draft.subject, subject) ||
last_available != available);
last_available = available;
if (dirty) {
// Update draft
draft.identity = ident;
draft.extra = extra;
draft.from = afrom;
draft.to = ato;
draft.cc = acc;
draft.bcc = abcc;
draft.subject = subject;
draft.sender = MessageHelper.getSortKey(draft.from);
Uri lookupUri = ContactInfo.getLookupUri(context, draft.from);
draft.avatar = (lookupUri == null ? null : lookupUri.toString());
db.message().updateMessage(draft);
}
if (action == R.id.action_undo || action == R.id.action_redo) {
if (draft.revision != null && draft.revisions != null) {
dirty = true;
if (action == R.id.action_undo) {
if (draft.revision > 1)
draft.revision--;
} else {
if (draft.revision < draft.revisions)
draft.revision++;
}
body = Helper.readText(draft.getFile(context, draft.revision));
Helper.writeText(draft.getFile(context), body);
db.message().setMessageRevision(draft.id, draft.revision);
db.message().setMessageContent(draft.id,
true,
draft.plain_only, // unchanged
HtmlHelper.getPreview(body),
null);
}
} else {
File file = draft.getFile(context);
if (!file.exists())
Helper.writeText(file, body);
String previous = Helper.readText(file);
if (!body.equals(previous)) {
dirty = true;
if (draft.revisions == null)
draft.revisions = 1;
else
draft.revisions++;
draft.revision = draft.revisions;
Helper.writeText(draft.getFile(context), body);
Helper.writeText(draft.getFile(context, draft.revisions), body);
db.message().setMessageRevision(draft.id, draft.revision);
db.message().setMessageRevisions(draft.id, draft.revisions);
db.message().setMessageContent(draft.id,
true,
draft.plain_only,
HtmlHelper.getPreview(body),
null);
}
}
if (dirty) {
draft.received = new Date().getTime();
db.message().setMessageReceived(draft.id, draft.received);
}
// Remove unused inline images
StringBuilder sb = new StringBuilder();
sb.append(body);
File rfile = draft.getRefFile(context);
if (rfile.exists())
sb.append(Helper.readText(rfile));
List cids = new ArrayList<>();
for (Element element : JsoupEx.parse(sb.toString()).select("img")) {
String src = element.attr("src");
if (src.startsWith("cid:"))
cids.add("<" + src.substring(4) + ">");
}
for (EntityAttachment attachment : new ArrayList<>(attachments))
if (attachment.isInline() && !cids.contains(attachment.cid)) {
Log.i("Removing unused inline attachment cid=" + attachment.cid);
db.attachment().deleteAttachment(attachment.id);
}
// Execute action
if (action == R.id.action_save ||
action == R.id.action_undo ||
action == R.id.action_redo ||
action == R.id.action_check) {
if (BuildConfig.DEBUG || dirty)
if (draft.encrypt == null || !draft.encrypt)
EntityOperation.queue(context, draft, EntityOperation.ADD);
if (action == R.id.action_check) {
// Check data
if (draft.identity == null)
throw new IllegalArgumentException(context.getString(R.string.title_from_missing));
if (draft.to == null && draft.cc == null && draft.bcc == null)
throw new IllegalArgumentException(context.getString(R.string.title_to_missing));
if (TextUtils.isEmpty(draft.subject))
args.putBoolean("remind_subject", true);
if (empty)
args.putBoolean("remind_text", true);
int attached = 0;
for (EntityAttachment attachment : attachments)
if (!attachment.available)
throw new IllegalArgumentException(context.getString(R.string.title_attachments_missing));
else if (!attachment.isInline() && attachment.encryption == null)
attached++;
// Check for missing attachments
if (attached == 0) {
List keywords = new ArrayList<>();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
String[] k = context.getString(R.string.title_attachment_keywords).split(",");
keywords.addAll(Arrays.asList(k));
} else {
Configuration config = context.getResources().getConfiguration();
LocaleList ll = context.getResources().getConfiguration().getLocales();
for (int i = 0; i < ll.size(); i++) {
Configuration lconf = new Configuration(config);
lconf.setLocale(ll.get(i));
Context lcontext = context.createConfigurationContext(lconf);
String[] k = lcontext.getString(R.string.title_attachment_keywords).split(",");
keywords.addAll(Arrays.asList(k));
}
}
String plain = HtmlHelper.getText(body);
for (String keyword : keywords)
if (plain.matches("(?si).*\\b" + Pattern.quote(keyword.trim()) + "\\b.*")) {
args.putBoolean("remind_attachment", true);
break;
}
}
} else {
Handler handler = new Handler(context.getMainLooper());
handler.post(new Runnable() {
public void run() {
ToastEx.makeText(context, R.string.title_draft_saved, Toast.LENGTH_LONG).show();
}
});
}
} else if (action == R.id.action_send) {
// Delete draft (cannot move to outbox)
EntityOperation.queue(context, draft, EntityOperation.DELETE);
File refDraftFile = draft.getRefFile(context);
// Copy message to outbox
draft.id = null;
draft.folder = db.folder().getOutbox().id;
draft.uid = null;
draft.ui_hide = false;
draft.id = db.message().insertMessage(draft);
Helper.writeText(draft.getFile(context), body);
if (refDraftFile.exists()) {
File refFile = draft.getRefFile(context);
refDraftFile.renameTo(refFile);
}
// Move attachments
for (EntityAttachment attachment : attachments)
db.attachment().setMessage(attachment.id, draft.id);
// Delay sending message
int send_delayed = prefs.getInt("send_delayed", 0);
if (draft.ui_snoozed == null && send_delayed != 0) {
draft.ui_snoozed = new Date().getTime() + send_delayed * 1000L;
db.message().setMessageSnoozed(draft.id, draft.ui_snoozed);
}
// Send message
if (draft.ui_snoozed == null)
EntityOperation.queue(context, draft, EntityOperation.SEND);
final String feedback;
if (draft.ui_snoozed == null)
feedback = context.getString(R.string.title_queued);
else {
DateFormat DTF = Helper.getDateTimeInstance(context);
feedback = context.getString(R.string.title_queued_at, DTF.format(draft.ui_snoozed));
}
Handler handler = new Handler(context.getMainLooper());
handler.post(new Runnable() {
public void run() {
ToastEx.makeText(context, feedback, Toast.LENGTH_LONG).show();
}
});
}
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
if (action == R.id.action_send && draft.ui_snoozed != null) {
Log.i("Delayed send id=" + draft.id + " at " + new Date(draft.ui_snoozed));
EntityMessage.snooze(context, draft.id, draft.ui_snoozed);
}
return draft;
}
@Override
protected void onExecuted(Bundle args, EntityMessage draft) {
int action = args.getInt("action");
Log.i("Loaded action id=" + (draft == null ? null : draft.id) + " action=" + getActionName(action));
etTo.setText(MessageHelper.formatAddressesCompose(draft.to));
etCc.setText(MessageHelper.formatAddressesCompose(draft.cc));
etBcc.setText(MessageHelper.formatAddressesCompose(draft.bcc));
bottom_navigation.getMenu().findItem(R.id.action_undo).setVisible(draft.revision != null && draft.revision > 1);
bottom_navigation.getMenu().findItem(R.id.action_redo).setVisible(draft.revision != null && !draft.revision.equals(draft.revisions));
if (action == R.id.action_delete) {
autosave = false;
finish();
} else if (action == R.id.action_undo || action == R.id.action_redo) {
showDraft(draft);
} else if (action == R.id.action_save) {
// Do nothing
} else if (action == R.id.action_check) {
boolean dialog = args.getBundle("extras").getBoolean("dialog");
boolean remind_subject = args.getBoolean("remind_subject", false);
boolean remind_text = args.getBoolean("remind_text", false);
boolean remind_attachment = args.getBoolean("remind_attachment", false);
if (dialog || remind_subject || remind_text || remind_attachment) {
setBusy(false);
FragmentDialogSend fragment = new FragmentDialogSend();
fragment.setArguments(args);
fragment.setTargetFragment(FragmentCompose.this, REQUEST_SEND);
fragment.show(getParentFragmentManager(), "compose:send");
} else
onActionSend(draft);
} else if (action == R.id.action_send) {
autosave = false;
finish();
}
}
@Override
protected void onException(Bundle args, Throwable ex) {
int action = args.getInt("action");
if (action == R.id.action_check)
setBusy(false);
if (ex instanceof MessageRemovedException)
finish();
else if (ex instanceof IllegalArgumentException ||
ex instanceof AddressException || ex instanceof UnknownHostException)
Snackbar.make(view, ex.getMessage(), Snackbar.LENGTH_LONG).show();
else
Helper.unexpectedError(getParentFragmentManager(), ex);
}
private String getActionName(int id) {
switch (id) {
case R.id.action_delete:
return "delete";
case R.id.action_undo:
return "undo";
case R.id.action_redo:
return "redo";
case R.id.action_save:
return "save";
case R.id.action_check:
return "check";
case R.id.action_send:
return "send";
default:
return Integer.toString(id);
}
}
private void setBusy(boolean busy) {
FragmentCompose.this.busy = busy;
Helper.setViewsEnabled(view, !busy);
getActivity().invalidateOptionsMenu();
}
};
private String unprefix(String subject, String prefix) {
subject = subject.trim();
prefix = prefix.trim().toLowerCase(Locale.ROOT);
while (subject.toLowerCase(Locale.ROOT).startsWith(prefix))
subject = subject.substring(prefix.length()).trim();
return subject;
}
private void showDraft(long id) {
Bundle args = new Bundle();
args.putLong("id", id);
new SimpleTask() {
@Override
protected EntityMessage onExecute(Context context, Bundle args) {
long id = args.getLong("id");
return DB.getInstance(context).message().getMessage(id);
}
@Override
protected void onExecuted(Bundle args, EntityMessage draft) {
showDraft(draft);
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(this, args, "compose:show");
}
private void showDraft(final EntityMessage draft) {
Bundle args = new Bundle();
args.putLong("id", draft.id);
args.putBoolean("show_images", show_images);
new SimpleTask() {
@Override
protected void onPostExecute(Bundle args) {
state = State.LOADED;
autosave = true;
pbWait.setVisibility(View.GONE);
media_bar.setVisibility(media ? View.VISIBLE : View.GONE);
bottom_navigation.getMenu().findItem(R.id.action_undo).setVisible(draft.revision != null && draft.revision > 1);
bottom_navigation.getMenu().findItem(R.id.action_redo).setVisible(draft.revision != null && !draft.revision.equals(draft.revisions));
bottom_navigation.setVisibility(View.VISIBLE);
Helper.setViewsEnabled(view, true);
getActivity().invalidateOptionsMenu();
}
@Override
protected Spanned[] onExecute(final Context context, Bundle args) throws Throwable {
final long id = args.getLong("id");
final boolean show_images = args.getBoolean("show_images", false);
int colorPrimary = Helper.resolveColor(context, R.attr.colorPrimary);
DB db = DB.getInstance(context);
EntityMessage draft = db.message().getMessage(id);
if (draft == null || !draft.content)
throw new IllegalArgumentException(context.getString(R.string.title_no_body));
String body = Helper.readText(draft.getFile(context));
Spanned spannedBody = HtmlHelper.fromHtml(body, new Html.ImageGetter() {
@Override
public Drawable getDrawable(String source) {
return ImageHelper.decodeImage(context, id, source, true, etBody);
}
}, null);
SpannableStringBuilder bodyBuilder = new SpannableStringBuilder(spannedBody);
QuoteSpan[] bodySpans = bodyBuilder.getSpans(0, bodyBuilder.length(), QuoteSpan.class);
for (QuoteSpan quoteSpan : bodySpans) {
bodyBuilder.setSpan(
new StyledQuoteSpan(context, colorPrimary),
bodyBuilder.getSpanStart(quoteSpan),
bodyBuilder.getSpanEnd(quoteSpan),
bodyBuilder.getSpanFlags(quoteSpan));
bodyBuilder.removeSpan(quoteSpan);
}
spannedBody = bodyBuilder;
Spanned spannedRef = null;
File refFile = draft.getRefFile(context);
if (refFile.exists()) {
String quote = HtmlHelper.sanitize(context, Helper.readText(refFile), show_images);
Spanned spannedQuote = HtmlHelper.fromHtml(quote,
new Html.ImageGetter() {
@Override
public Drawable getDrawable(String source) {
return ImageHelper.decodeImage(context, id, source, show_images, tvReference);
}
},
null);
SpannableStringBuilder refBuilder = new SpannableStringBuilder(spannedQuote);
QuoteSpan[] refSpans = refBuilder.getSpans(0, refBuilder.length(), QuoteSpan.class);
for (QuoteSpan quoteSpan : refSpans) {
refBuilder.setSpan(
new StyledQuoteSpan(context, colorPrimary),
refBuilder.getSpanStart(quoteSpan),
refBuilder.getSpanEnd(quoteSpan),
refBuilder.getSpanFlags(quoteSpan));
refBuilder.removeSpan(quoteSpan);
}
spannedRef = refBuilder;
}
args.putBoolean("ref_has_images", spannedRef != null &&
spannedRef.getSpans(0, spannedRef.length(), ImageSpan.class).length > 0);
return new Spanned[]{spannedBody, spannedRef};
}
@Override
protected void onExecuted(Bundle args, Spanned[] text) {
etBody.setText(text[0]);
etBody.setSelection(0);
grpBody.setVisibility(View.VISIBLE);
cbSignature.setChecked(draft.signature);
tvSignature.setAlpha(draft.signature ? 1.0f : Helper.LOW_LIGHT);
boolean ref_has_images = args.getBoolean("ref_has_images");
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
boolean ref_hint = prefs.getBoolean("compose_reference", true);
tvReference.setText(text[1]);
tvReference.setVisibility(text[1] == null ? View.GONE : View.VISIBLE);
grpReferenceHint.setVisibility(text[1] == null || !ref_hint ? View.GONE : View.VISIBLE);
ibReferenceDelete.setVisibility(text[1] == null ? View.GONE : View.VISIBLE);
ibReferenceEdit.setVisibility(text[1] == null ? View.GONE : View.VISIBLE);
ibReferenceImages.setVisibility(ref_has_images && !show_images ? View.VISIBLE : View.GONE);
final Context context = getContext();
new Handler().post(new Runnable() {
@Override
public void run() {
View target;
if (TextUtils.isEmpty(etTo.getText().toString().trim()))
target = etTo;
else if (TextUtils.isEmpty(etSubject.getText().toString()))
target = etSubject;
else
target = etBody;
target.requestFocus();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean keyboard = prefs.getBoolean("keyboard", true);
if (keyboard) {
InputMethodManager imm =
(InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null)
imm.showSoftInput(target, InputMethodManager.SHOW_IMPLICIT);
}
}
});
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(this, args, "compose:show");
}
private AdapterView.OnItemSelectedListener identitySelected = new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
EntityIdentity identity = (EntityIdentity) parent.getAdapter().getItem(position);
int at = (identity == null ? -1 : identity.email.indexOf('@'));
etExtra.setHint(at < 0 ? null : identity.email.substring(0, at));
tvDomain.setText(at < 0 ? null : identity.email.substring(at));
grpExtra.setVisibility(identity != null && identity.sender_extra ? View.VISIBLE : View.GONE);
Spanned signature = null;
if (identity != null && !TextUtils.isEmpty(identity.signature))
signature = HtmlHelper.fromHtml(identity.signature, new Html.ImageGetter() {
@Override
public Drawable getDrawable(String source) {
int px = Helper.dp2pixels(getContext(), 24);
Drawable d = getContext().getResources()
.getDrawable(R.drawable.baseline_image_24, getContext().getTheme());
d.setBounds(0, 0, px, px);
return d;
}
}, null);
tvSignature.setText(signature);
grpSignature.setVisibility(signature == null ? View.GONE : View.VISIBLE);
}
@Override
public void onNothingSelected(AdapterView> parent) {
etExtra.setHint("");
tvDomain.setText(null);
tvSignature.setText(null);
grpSignature.setVisibility(View.GONE);
}
};
private ActivityBase.IBackPressedListener onBackPressedListener = new ActivityBase.IBackPressedListener() {
@Override
public boolean onBackPressed() {
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED))
onExit();
return true;
}
};
public static class FragmentDialogContactGroup extends FragmentDialogBase {
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
final long working = getArguments().getLong("working");
View dview = LayoutInflater.from(getContext()).inflate(R.layout.dialog_contact_group, null);
final Spinner spGroup = dview.findViewById(R.id.spGroup);
final Spinner spTarget = dview.findViewById(R.id.spTarget);
Cursor groups = getContext().getContentResolver().query(
ContactsContract.Groups.CONTENT_SUMMARY_URI,
new String[]{
ContactsContract.Groups._ID,
ContactsContract.Groups.TITLE,
ContactsContract.Groups.SUMMARY_COUNT
},
ContactsContract.Groups.DELETED + " = 0" +
" AND " + ContactsContract.Groups.SUMMARY_COUNT + " > 0",
null,
ContactsContract.Groups.TITLE
);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
getContext(),
R.layout.spinner_item1_dropdown,
groups,
new String[]{ContactsContract.Groups.TITLE},
new int[]{android.R.id.text1},
0);
spGroup.setAdapter(adapter);
return new AlertDialog.Builder(getContext())
.setView(dview)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
int target = spTarget.getSelectedItemPosition();
Cursor cursor = (Cursor) spGroup.getSelectedItem();
if (target != INVALID_POSITION && cursor != null) {
long group = cursor.getLong(0);
Bundle args = getArguments();
args.putLong("id", working);
args.putInt("target", target);
args.putLong("group", group);
sendResult(RESULT_OK);
} else
sendResult(RESULT_CANCELED);
}
})
.setNegativeButton(android.R.string.cancel, null)
.create();
}
}
public static class FragmentDialogAnswer extends FragmentDialogBase {
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
final ArrayAdapter adapter =
new ArrayAdapter<>(getContext(), R.layout.spinner_item1, android.R.id.text1);
// TODO: spinner
new SimpleTask>() {
@Override
protected List onExecute(Context context, Bundle args) {
DB db = DB.getInstance(getContext());
return db.answer().getAnswers(false);
}
@Override
protected void onExecuted(Bundle args, List answers) {
adapter.addAll(answers);
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(this, new Bundle(), "compose:answer");
return new AlertDialog.Builder(getContext())
.setTitle(R.string.title_insert_template)
.setAdapter(adapter, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
EntityAnswer answer = adapter.getItem(which);
getArguments().putString("answer", answer.text);
sendResult(RESULT_OK);
}
})
.setNegativeButton(android.R.string.cancel, null)
.create();
}
}
public static class FragmentDialogSend extends FragmentDialogBase {
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
long id = getArguments().getLong("id");
Bundle args = getArguments();
boolean dialog = args.getBundle("extras").getBoolean("dialog");
boolean remind_subject = args.getBoolean("remind_subject", false);
boolean remind_text = args.getBoolean("remind_text", false);
boolean remind_attachment = args.getBoolean("remind_attachment", false);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
int send_delayed = prefs.getInt("send_delayed", 0);
boolean send_dialog = prefs.getBoolean("send_dialog", true);
final int[] sendDelayedValues = getResources().getIntArray(R.array.sendDelayedValues);
final String[] sendDelayedNames = getResources().getStringArray(R.array.sendDelayedNames);
final ViewGroup dview = (ViewGroup) LayoutInflater.from(getContext()).inflate(R.layout.dialog_send, null);
final TextView tvRemindSubject = dview.findViewById(R.id.tvRemindSubject);
final TextView tvRemindText = dview.findViewById(R.id.tvRemindText);
final TextView tvRemindAttachment = dview.findViewById(R.id.tvRemindAttachment);
final TextView tvTo = dview.findViewById(R.id.tvTo);
final TextView tvVia = dview.findViewById(R.id.tvVia);
final CheckBox cbPlainOnly = dview.findViewById(R.id.cbPlainOnly);
final CheckBox cbEncrypt = dview.findViewById(R.id.cbEncrypt);
final CheckBox cbReceipt = dview.findViewById(R.id.cbReceipt);
final TextView tvReceipt = dview.findViewById(R.id.tvReceipt);
final Spinner spPriority = dview.findViewById(R.id.spPriority);
final TextView tvSendAt = dview.findViewById(R.id.tvSendAt);
final ImageButton ibSendAt = dview.findViewById(R.id.ibSendAt);
final CheckBox cbNotAgain = dview.findViewById(R.id.cbNotAgain);
final TextView tvNotAgain = dview.findViewById(R.id.tvNotAgain);
tvRemindSubject.setVisibility(remind_subject ? View.VISIBLE : View.GONE);
tvRemindText.setVisibility(remind_text ? View.VISIBLE : View.GONE);
tvRemindAttachment.setVisibility(remind_attachment ? View.VISIBLE : View.GONE);
tvTo.setText(null);
tvVia.setText(null);
tvReceipt.setVisibility(View.GONE);
spPriority.setTag(1);
spPriority.setSelection(1);
tvSendAt.setText(null);
cbNotAgain.setChecked(!send_dialog);
cbNotAgain.setVisibility(dialog ? View.VISIBLE : View.GONE);
tvNotAgain.setVisibility(cbNotAgain.isChecked() && send_dialog ? View.VISIBLE : View.GONE);
Helper.setViewsEnabled(dview, false);
cbNotAgain.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
prefs.edit().putBoolean("send_dialog", !isChecked).apply();
tvNotAgain.setVisibility(isChecked && send_dialog ? View.VISIBLE : View.GONE);
}
});
cbPlainOnly.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
Bundle args = new Bundle();
args.putLong("id", id);
args.putBoolean("plain_only", checked);
new SimpleTask() {
@Override
protected Void onExecute(Context context, Bundle args) {
long id = args.getLong("id");
boolean plain_only = args.getBoolean("plain_only");
DB db = DB.getInstance(context);
db.message().setMessagePlainOnly(id, plain_only);
return null;
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(FragmentDialogSend.this, args, "compose:plain_only");
}
});
cbEncrypt.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
Bundle args = new Bundle();
args.putLong("id", id);
args.putBoolean("encrypt", checked);
new SimpleTask() {
@Override
protected Void onExecute(Context context, Bundle args) {
long id = args.getLong("id");
boolean encrypt = args.getBoolean("encrypt");
DB db = DB.getInstance(context);
db.message().setMessageEncrypt(id, encrypt);
return null;
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(FragmentDialogSend.this, args, "compose:encrypt");
}
});
cbReceipt.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
tvReceipt.setVisibility(checked ? View.VISIBLE : View.GONE);
Bundle args = new Bundle();
args.putLong("id", id);
args.putBoolean("receipt", checked);
new SimpleTask() {
@Override
protected Void onExecute(Context context, Bundle args) {
long id = args.getLong("id");
boolean receipt = args.getBoolean("receipt");
DB db = DB.getInstance(context);
db.message().setMessageReceiptRequest(id, receipt);
return null;
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(FragmentDialogSend.this, args, "compose:receipt");
}
});
spPriority.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
int last = (int) spPriority.getTag();
if (last != position) {
spPriority.setTag(position);
setPriority(position);
}
}
@Override
public void onNothingSelected(AdapterView> parent) {
spPriority.setTag(1);
setPriority(1);
}
private void setPriority(int priority) {
Bundle args = new Bundle();
args.putLong("id", id);
args.putInt("priority", priority);
new SimpleTask() {
@Override
protected Void onExecute(Context context, Bundle args) {
long id = args.getLong("id");
int priority = args.getInt("priority");
DB db = DB.getInstance(context);
db.message().setMessagePriority(id, priority);
return null;
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(FragmentDialogSend.this, args, "compose:priority");
}
});
ibSendAt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Bundle args = new Bundle();
args.putString("title", getString(R.string.title_send_at));
args.putLong("id", id);
FragmentDialogDuration fragment = new FragmentDialogDuration();
fragment.setArguments(args);
fragment.setTargetFragment(FragmentDialogSend.this, 1);
fragment.show(getParentFragmentManager(), "send:snooze");
}
});
DB db = DB.getInstance(getContext());
db.message().liveMessage(id).observe(getViewLifecycleOwner(), new Observer() {
@Override
public void onChanged(TupleMessageEx draft) {
if (draft == null) {
dismiss();
return;
}
int plus = (draft.cc == null ? 0 : draft.cc.length) +
(draft.bcc == null ? 0 : draft.bcc.length);
tvTo.setText(MessageHelper.formatAddressesShort(draft.to) + (plus > 0 ? " +" + plus : ""));
tvVia.setText(draft.identityEmail);
cbPlainOnly.setChecked(draft.plain_only != null && draft.plain_only);
cbEncrypt.setChecked(draft.encrypt != null && draft.encrypt);
cbReceipt.setChecked(draft.receipt_request != null && draft.receipt_request);
cbPlainOnly.setVisibility(draft.receipt != null && draft.receipt ? View.GONE : View.VISIBLE);
cbEncrypt.setVisibility(draft.receipt != null && draft.receipt ? View.GONE : View.VISIBLE);
cbReceipt.setVisibility(draft.receipt != null && draft.receipt ? View.GONE : View.VISIBLE);
int priority = (draft.priority == null ? 1 : draft.priority);
spPriority.setTag(priority);
spPriority.setSelection(priority);
if (draft.ui_snoozed == null) {
if (send_delayed == 0)
tvSendAt.setText(getString(R.string.title_now));
else
for (int pos = 0; pos < sendDelayedValues.length; pos++)
if (sendDelayedValues[pos] == send_delayed) {
tvSendAt.setText(getString(R.string.title_after, sendDelayedNames[pos]));
break;
}
} else {
DateFormat DTF = Helper.getDateTimeInstance(getContext(), SimpleDateFormat.MEDIUM, SimpleDateFormat.SHORT);
DateFormat D = new SimpleDateFormat("E");
tvSendAt.setText(D.format(draft.ui_snoozed) + " " + DTF.format(draft.ui_snoozed));
}
Helper.setViewsEnabled(dview, true);
}
});
return new AlertDialog.Builder(getContext())
.setView(dview)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
sendResult(Activity.RESULT_OK);
}
})
.setNegativeButton(android.R.string.cancel, null)
.create();
}
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (resultCode == RESULT_OK && intent != null) {
Bundle data = intent.getBundleExtra("args");
long id = data.getLong("id");
long duration = data.getLong("duration");
long time = data.getLong("time");
Bundle args = new Bundle();
args.putLong("id", id);
args.putLong("wakeup", duration == 0 ? -1 : time);
new SimpleTask() {
@Override
protected Void onExecute(Context context, Bundle args) {
long id = args.getLong("id");
long wakeup = args.getLong("wakeup");
DB db = DB.getInstance(context);
db.message().setMessageSnoozed(id, wakeup < 0 ? null : wakeup);
return null;
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(this, args, "compose:snooze");
}
}
}
private class DraftData {
private EntityMessage draft;
private List identities;
}
}