diff --git a/app/src/main/java/eu/faircode/email/AdapterMessage.java b/app/src/main/java/eu/faircode/email/AdapterMessage.java index ecbd7e2eab..1e9ac72274 100644 --- a/app/src/main/java/eu/faircode/email/AdapterMessage.java +++ b/app/src/main/java/eu/faircode/email/AdapterMessage.java @@ -143,6 +143,7 @@ public class AdapterMessage extends RecyclerView.Adapter() { - @Override - protected void onPreExecute(Bundle args) { - ivAvatar.setVisibility(avatars ? View.INVISIBLE : View.GONE); - tvFrom.setText(MessageHelper.formatAddresses(addresses, !compact, false)); - } - - @Override - protected ContactInfo onExecute(Context context, Bundle args) { - Address[] addresses = (Address[]) args.getSerializable("addresses"); - return ContactInfo.get(context, addresses, false); - } - - @Override - protected void onExecuted(Bundle args, ContactInfo info) { - long id = args.getLong("id"); - TupleMessageEx amessage = getMessage(); - if (amessage == null || !amessage.id.equals(id)) - return; - - showContactInfo(info, message); - } + // Unseen + int typeface = (message.unseen > 0 ? Typeface.BOLD : Typeface.NORMAL); + tvFrom.setTypeface(null, typeface); + tvSize.setTypeface(null, typeface); + tvTime.setTypeface(null, typeface); + tvSubject.setTypeface(null, typeface | Typeface.ITALIC); + tvCount.setTypeface(null, typeface); - @Override - protected void onException(Bundle args, Throwable ex) { - Helper.unexpectedError(context, owner, ex); - } - }.execute(context, owner, aargs, "message:avatar"); - } else - showContactInfo(info, message); + int colorUnseen = (message.unseen > 0 ? colorUnread : textColorSecondary); + tvFrom.setTextColor(colorUnseen); + tvSize.setTextColor(colorUnseen); + tvTime.setTextColor(colorUnseen); + // Account color vwColor.setBackgroundColor(message.accountColor == null ? Color.TRANSPARENT : message.accountColor); vwColor.setVisibility(View.VISIBLE); - ivExpander.setImageResource(show_expanded ? R.drawable.baseline_expand_less_24 : R.drawable.baseline_expand_more_24); + // Expander + boolean expanded = (viewType == ViewType.THREAD && properties.getValue("expanded", message.id)); + ivExpander.setImageResource(expanded ? R.drawable.baseline_expand_less_24 : R.drawable.baseline_expand_more_24); if (viewType == ViewType.THREAD && threading) ivExpander.setVisibility(EntityFolder.DRAFTS.equals(message.folderType) ? View.INVISIBLE : View.VISIBLE); else ivExpander.setVisibility(View.GONE); - bindFlagged(message); - + // Line 1 tvSize.setText(message.size == null ? null : Helper.humanReadableByteCount(message.size, true)); tvSize.setVisibility(message.size == null || message.content ? View.GONE : View.VISIBLE); tvTime.setText(date && "time".equals(sort) ? tf.format(message.received) : DateUtils.getRelativeTimeSpanString(context, message.received)); + // Line 2 + tvSubject.setText(message.subject); + + // Line 3 ivDraft.setVisibility(message.drafts > 0 ? View.VISIBLE : View.GONE); ivSnoozed.setVisibility(message.ui_snoozed == null ? View.GONE : View.VISIBLE); ivBrowsed.setVisibility(message.ui_browsed ? View.VISIBLE : View.GONE); ivAnswered.setVisibility(message.ui_answered ? View.VISIBLE : View.GONE); ivAttachments.setVisibility(message.attachments > 0 ? View.VISIBLE : View.GONE); - cbInline.setVisibility(View.GONE); - btnDownloadAttachments.setVisibility(View.GONE); - btnSaveAttachments.setVisibility(View.GONE); - tvNoInternetAttachments.setVisibility(View.GONE); - tvSubject.setText(message.subject); if (viewType == ViewType.FOLDER) tvFolder.setText(message.accountName); @@ -579,9 +553,6 @@ public class AdapterMessage extends RecyclerView.Adapter 0 ? Typeface.BOLD : Typeface.NORMAL); - tvFrom.setTypeface(null, typeface); - tvSize.setTypeface(null, typeface); - tvTime.setTypeface(null, typeface); - tvSubject.setTypeface(null, typeface | Typeface.ITALIC); - tvCount.setTypeface(null, typeface); - - int colorUnseen = (message.unseen > 0 ? colorUnread : textColorSecondary); - tvFrom.setTextColor(colorUnseen); - tvSize.setTextColor(colorUnseen); - tvTime.setTextColor(colorUnseen); - - grpExpanded.setVisibility(viewType == ViewType.THREAD && show_expanded ? View.VISIBLE : View.GONE); - grpAddress.setVisibility(viewType == ViewType.THREAD && show_expanded && show_addresses ? View.VISIBLE : View.GONE); - tvFlags.setVisibility(View.GONE); - tvKeywords.setVisibility(View.GONE); - ivSearchContact.setVisibility( - viewType == ViewType.THREAD && show_expanded && show_addresses && - search && BuildConfig.DEBUG - ? View.VISIBLE : View.GONE); - ivAddContact.setVisibility( - viewType == ViewType.THREAD && show_expanded && show_addresses && - contacts && message.from != null && message.from.length > 0 - ? View.VISIBLE : View.GONE); - - if (show_headers && show_expanded && message.headers == null) { - pbHeaders.setVisibility(internet ? View.VISIBLE : View.GONE); - tvNoInternetHeaders.setVisibility(internet ? View.GONE : View.VISIBLE); - } else { - pbHeaders.setVisibility(View.GONE); - tvNoInternetHeaders.setVisibility(View.GONE); - } - - rvImage.setVisibility(View.GONE); - - grpHeaders.setVisibility(show_headers && show_expanded ? View.VISIBLE : View.GONE); - grpAttachments.setVisibility(message.attachments > 0 && show_expanded ? View.VISIBLE : View.GONE); - btnHtml.setVisibility(viewType == ViewType.THREAD && show_expanded && !show_html ? View.INVISIBLE : View.GONE); - ibQuotes.setVisibility(viewType == ViewType.THREAD && show_expanded && !show_html ? View.INVISIBLE : View.GONE); - ibImages.setVisibility(viewType == ViewType.THREAD && show_expanded && !show_html ? View.INVISIBLE : View.GONE); - tvBody.setVisibility(viewType == ViewType.THREAD && show_expanded && !show_html ? View.INVISIBLE : View.GONE); - vwBody.setVisibility(viewType == ViewType.THREAD && show_expanded && show_html ? View.INVISIBLE : View.GONE); - pbBody.setVisibility(View.GONE); - tvNoInternetBody.setVisibility(View.GONE); - - bnvActions.setTag(null); - - if (show_expanded) { - ivExpanderAddress.setImageResource(show_addresses ? R.drawable.baseline_expand_less_24 : R.drawable.baseline_expand_more_24); - - tvFromEx.setText(MessageHelper.formatAddresses(message.from)); - tvTo.setText(MessageHelper.formatAddresses(message.to)); - tvReplyTo.setText(MessageHelper.formatAddresses(message.reply)); - tvCc.setText(MessageHelper.formatAddresses(message.cc)); - tvBcc.setText(MessageHelper.formatAddresses(message.bcc)); - - tvTimeEx.setText(dtf.format(message.received)); - - tvSizeEx.setText(message.size == null ? null : Helper.humanReadableByteCount(message.size, true)); - if (!message.duplicate) - tvSizeEx.setAlpha(message.content ? 1.0f : Helper.LOW_LIGHT); - tvSizeEx.setVisibility(message.size == null ? View.GONE : View.VISIBLE); - - tvSubjectEx.setText(message.subject); - tvFlags.setText(message.flags); - tvFlags.setVisibility(BuildConfig.DEBUG ? View.VISIBLE : View.GONE); - tvKeywords.setText(TextUtils.join(" ", message.keywords)); - tvKeywords.setVisibility(message.keywords.length > 0 ? View.VISIBLE : View.GONE); - - if (show_headers && message.headers != null) { - SpannableStringBuilder ssb = new SpannableStringBuilder(message.headers); - int index = 0; - for (String line : message.headers.split("\n")) { - if (line.length() > 0 && !Character.isWhitespace(line.charAt(0))) { - int colon = line.indexOf(':'); - if (colon > 0) - ssb.setSpan(new StyleSpan(Typeface.BOLD), index, index + colon, 0); - } - index += line.length() + 1; - } - - tvHeaders.setText(ssb); - } else - tvHeaders.setText(null); - - for (int i = 0; i < bnvActions.getMenu().size(); i++) - bnvActions.getMenu().getItem(i).setVisible(false); - - if (textSize != 0) - tvBody.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); - - Spanned body = properties.getBody(message.id); - tvBody.setText(body); - tvBody.setMovementMethod(null); - if (internet || message.content) - pbBody.setVisibility(View.VISIBLE); - else - tvNoInternetBody.setVisibility(View.VISIBLE); - - if (body == null && message.content) - if (show_html) - onShowHtmlConfirmed(message); - else { - Bundle args = new Bundle(); - args.putSerializable("message", message); - bodyTask.execute(context, owner, args, "message:body"); - } - - List attachments = idAttachments.get(message.id); - if (attachments != null) - adapterAttachment.set(attachments); + // Contact info + boolean outgoing = (viewType != ViewType.THREAD && EntityFolder.isOutgoing(message.folderType)); + Address[] addresses = (outgoing ? message.to : message.from); + ContactInfo info = ContactInfo.get(context, addresses, true); + if (info == null) { + Bundle aargs = new Bundle(); + aargs.putLong("id", message.id); + aargs.putSerializable("addresses", addresses); - // Observe attachments - observerAttachments = new Observer>() { + new SimpleTask() { @Override - public void onChanged(@Nullable List attachments) { - if (attachments == null) - attachments = new ArrayList<>(); - idAttachments.put(message.id, attachments); - - boolean show_inline = properties.getValue("inline", message.id); - Log.i("Show inline=" + show_inline); - - boolean inline = false; - boolean download = false; - boolean save = (attachments.size() > 1); - boolean downloading = false; - List a = new ArrayList<>(); - for (EntityAttachment attachment : attachments) { - if (attachment.isInline()) - inline = true; - if (attachment.progress == null && !attachment.available) - download = true; - if (!attachment.available) - save = false; - if (attachment.progress != null) - downloading = true; - if (show_inline || !attachment.isInline()) - a.add(attachment); - } - adapterAttachment.set(a); - - cbInline.setOnCheckedChangeListener(null); - cbInline.setChecked(show_inline); - cbInline.setVisibility(inline ? View.VISIBLE : View.GONE); - btnDownloadAttachments.setVisibility(download && internet ? View.VISIBLE : View.GONE); - btnSaveAttachments.setVisibility(save ? View.VISIBLE : View.GONE); - tvNoInternetAttachments.setVisibility(downloading && !internet ? View.VISIBLE : View.GONE); - - cbInline.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - properties.setValue("inline", message.id, isChecked); - liveAttachments.removeObserver(observerAttachments); - liveAttachments.observe(owner, observerAttachments); - } - }); - - List images = new ArrayList<>(); - for (EntityAttachment attachment : attachments) - if (attachment.type.startsWith("image/") && !attachment.isInline()) - images.add(attachment); - adapterImage.set(images); - rvImage.setVisibility(images.size() > 0 ? View.VISIBLE : View.GONE); - - if (message.content && !show_html) { - Bundle args = new Bundle(); - args.putSerializable("message", message); - bodyTask.execute(context, owner, args, "message:body"); - } + protected void onPreExecute(Bundle args) { + Address[] addresses = (Address[]) args.getSerializable("addresses"); + ivAvatar.setVisibility(avatars ? View.INVISIBLE : View.GONE); + tvFrom.setText(MessageHelper.formatAddresses(addresses, !compact, false)); } - }; - liveAttachments = db.attachment().liveAttachments(message.id); - liveAttachments.observe(owner, observerAttachments); - // Setup action - Bundle sargs = new Bundle(); - sargs.putLong("id", message.id); - sargs.putLong("account", message.account); - - new SimpleTask>() { @Override - protected List onExecute(Context context, Bundle args) { - long account = args.getLong("account"); - return DB.getInstance(context).folder().getSystemFolders(account); + protected ContactInfo onExecute(Context context, Bundle args) { + Address[] addresses = (Address[]) args.getSerializable("addresses"); + return ContactInfo.get(context, addresses, false); } @Override - protected void onExecuted(Bundle args, List folders) { + protected void onExecuted(Bundle args, ContactInfo info) { long id = args.getLong("id"); TupleMessageEx amessage = getMessage(); if (amessage == null || !amessage.id.equals(id)) return; - boolean hasArchive = false; - boolean hasTrash = false; - boolean hasJunk = false; - if (folders != null) - for (EntityFolder folder : folders) { - if (EntityFolder.ARCHIVE.equals(folder.type)) - hasArchive = true; - else if (EntityFolder.TRASH.equals(folder.type)) - hasTrash = true; - else if (EntityFolder.JUNK.equals(folder.type)) - hasJunk = true; - } - - boolean inOutbox = EntityFolder.OUTBOX.equals(message.folderType); - boolean inArchive = EntityFolder.ARCHIVE.equals(message.folderType); - boolean inTrash = EntityFolder.TRASH.equals(message.folderType); - - ActionData data = new ActionData(); - data.hasJunk = hasJunk; - data.delete = (inTrash || !hasTrash || inOutbox); - data.message = message; - bnvActions.setTag(data); - - bnvActions.getMenu().findItem(R.id.action_more).setVisible(!inOutbox); - - bnvActions.getMenu().findItem(R.id.action_delete).setVisible( - (inTrash && message.msgid != null) || - (!inTrash && hasTrash && message.uid != null) || - (inOutbox && !TextUtils.isEmpty(message.error))); - bnvActions.getMenu().findItem(R.id.action_delete).setTitle(inTrash ? R.string.title_delete : R.string.title_trash); - - bnvActions.getMenu().findItem(R.id.action_move).setVisible( - message.uid != null || (inOutbox && (message.ui_snoozed != null || message.error != null))); - bnvActions.getMenu().findItem(R.id.action_move).setTitle( - inOutbox && (message.ui_snoozed != null || message.error != null) - ? R.string.title_folder_drafts : R.string.title_move); - - bnvActions.getMenu().findItem(R.id.action_archive).setVisible(message.uid != null && !inArchive && hasArchive); - bnvActions.getMenu().findItem(R.id.action_reply).setEnabled(message.content); - bnvActions.getMenu().findItem(R.id.action_reply).setVisible(!inOutbox); + bindContactInfo(info, message); } @Override protected void onException(Bundle args, Throwable ex) { Helper.unexpectedError(context, owner, ex); } - }.execute(context, owner, sargs, "message:actions"); + }.execute(context, owner, aargs, "message:avatar"); } else - properties.setBody(message.id, null); - - itemView.setActivated(selectionTracker != null && selectionTracker.isSelected(message.id)); + bindContactInfo(info, message); } private void bindFlagged(TupleMessageEx message) { @@ -871,7 +644,35 @@ public class AdapterMessage extends RecyclerView.Adapter 0 ? View.VISIBLE : View.GONE); + + grpHeaders.setVisibility(show_headers ? View.VISIBLE : View.GONE); + if (show_headers && message.headers == null) { + pbHeaders.setVisibility(internet ? View.VISIBLE : View.GONE); + tvNoInternetHeaders.setVisibility(internet ? View.GONE : View.VISIBLE); + } + + grpAttachments.setVisibility(message.attachments > 0 ? View.VISIBLE : View.GONE); + + bnvActions.setTag(null); + for (int i = 0; i < bnvActions.getMenu().size(); i++) + bnvActions.getMenu().getItem(i).setVisible(false); + + btnHtml.setVisibility(!show_html ? View.INVISIBLE : View.GONE); + ibQuotes.setVisibility(!show_html ? View.INVISIBLE : View.GONE); + ibImages.setVisibility(!show_html ? View.INVISIBLE : View.GONE); + tvBody.setVisibility(!show_html ? View.INVISIBLE : View.GONE); + vwBody.setVisibility(show_html ? View.INVISIBLE : View.GONE); + + // Addresses + ivExpanderAddress.setImageResource(show_addresses ? R.drawable.baseline_expand_less_24 : R.drawable.baseline_expand_more_24); + tvFromEx.setText(MessageHelper.formatAddresses(message.from)); + tvTo.setText(MessageHelper.formatAddresses(message.to)); + tvReplyTo.setText(MessageHelper.formatAddresses(message.reply)); + tvCc.setText(MessageHelper.formatAddresses(message.cc)); + tvBcc.setText(MessageHelper.formatAddresses(message.bcc)); + + tvTimeEx.setText(dtf.format(message.received)); + + tvSizeEx.setText(message.size == null ? null : Helper.humanReadableByteCount(message.size, true)); + if (!message.duplicate) + tvSizeEx.setAlpha(message.content ? 1.0f : Helper.LOW_LIGHT); + tvSizeEx.setVisibility(message.size == null ? View.GONE : View.VISIBLE); + + tvSubjectEx.setText(message.subject); + + // Flags + tvFlags.setText(message.flags); + tvFlags.setVisibility(BuildConfig.DEBUG ? View.VISIBLE : View.GONE); + + // Keywords + tvKeywords.setText(TextUtils.join(" ", message.keywords)); + tvKeywords.setVisibility(message.keywords.length > 0 ? View.VISIBLE : View.GONE); + + // Headers + if (show_headers && message.headers != null) { + SpannableStringBuilder ssb = new SpannableStringBuilder(message.headers); + int index = 0; + for (String line : message.headers.split("\n")) { + if (line.length() > 0 && !Character.isWhitespace(line.charAt(0))) { + int colon = line.indexOf(':'); + if (colon > 0) + ssb.setSpan(new StyleSpan(Typeface.BOLD), index, index + colon, 0); + } + index += line.length() + 1; + } + + tvHeaders.setText(ssb); + } else + tvHeaders.setText(null); + + // Attachments + List attachments = idAttachments.get(message.id); + if (attachments != null) + adapterAttachment.set(attachments); + + // Observe attachments + observerAttachments = new Observer>() { + @Override + public void onChanged(@Nullable List attachments) { + if (attachments == null) + attachments = new ArrayList<>(); + idAttachments.put(message.id, attachments); + + boolean show_inline = properties.getValue("inline", message.id); + Log.i("Show inline=" + show_inline); + + boolean inline = false; + boolean download = false; + boolean save = (attachments.size() > 1); + boolean downloading = false; + List a = new ArrayList<>(); + for (EntityAttachment attachment : attachments) { + if (attachment.isInline()) + inline = true; + if (attachment.progress == null && !attachment.available) + download = true; + if (!attachment.available) + save = false; + if (attachment.progress != null) + downloading = true; + if (show_inline || !attachment.isInline()) + a.add(attachment); + } + adapterAttachment.set(a); + + cbInline.setOnCheckedChangeListener(null); + cbInline.setChecked(show_inline); + cbInline.setVisibility(inline ? View.VISIBLE : View.GONE); + btnDownloadAttachments.setVisibility(download && internet ? View.VISIBLE : View.GONE); + btnSaveAttachments.setVisibility(save ? View.VISIBLE : View.GONE); + tvNoInternetAttachments.setVisibility(downloading && !internet ? View.VISIBLE : View.GONE); + + cbInline.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + properties.setValue("inline", message.id, isChecked); + liveAttachments.removeObserver(observerAttachments); + liveAttachments.observe(owner, observerAttachments); + } + }); + + List images = new ArrayList<>(); + for (EntityAttachment attachment : attachments) + if (attachment.type.startsWith("image/") && !attachment.isInline()) + images.add(attachment); + adapterImage.set(images); + rvImage.setVisibility(images.size() > 0 ? View.VISIBLE : View.GONE); + + boolean show_html = properties.getValue("html", message.id); + if (message.content && !show_html) { + Bundle args = new Bundle(); + args.putSerializable("message", message); + bodyTask.execute(context, owner, args, "message:body"); + } + } + }; + liveAttachments = db.attachment().liveAttachments(message.id); + liveAttachments.observe(owner, observerAttachments); + + // Setup actions + Bundle sargs = new Bundle(); + sargs.putLong("id", message.id); + sargs.putLong("account", message.account); + + new SimpleTask>() { + @Override + protected List onExecute(Context context, Bundle args) { + long account = args.getLong("account"); + return DB.getInstance(context).folder().getSystemFolders(account); + } + + @Override + protected void onExecuted(Bundle args, List folders) { + long id = args.getLong("id"); + TupleMessageEx amessage = getMessage(); + if (amessage == null || !amessage.id.equals(id)) + return; + + boolean hasArchive = false; + boolean hasTrash = false; + boolean hasJunk = false; + if (folders != null) + for (EntityFolder folder : folders) { + if (EntityFolder.ARCHIVE.equals(folder.type)) + hasArchive = true; + else if (EntityFolder.TRASH.equals(folder.type)) + hasTrash = true; + else if (EntityFolder.JUNK.equals(folder.type)) + hasJunk = true; + } + + boolean inOutbox = EntityFolder.OUTBOX.equals(message.folderType); + boolean inArchive = EntityFolder.ARCHIVE.equals(message.folderType); + boolean inTrash = EntityFolder.TRASH.equals(message.folderType); + + ActionData data = new ActionData(); + data.hasJunk = hasJunk; + data.delete = (inTrash || !hasTrash || inOutbox); + data.message = message; + bnvActions.setTag(data); + + bnvActions.getMenu().findItem(R.id.action_more).setVisible(!inOutbox); + + bnvActions.getMenu().findItem(R.id.action_delete).setVisible( + (inTrash && message.msgid != null) || + (!inTrash && hasTrash && message.uid != null) || + (inOutbox && !TextUtils.isEmpty(message.error))); + bnvActions.getMenu().findItem(R.id.action_delete).setTitle(inTrash ? R.string.title_delete : R.string.title_trash); + + bnvActions.getMenu().findItem(R.id.action_move).setVisible( + message.uid != null || (inOutbox && (message.ui_snoozed != null || message.error != null))); + bnvActions.getMenu().findItem(R.id.action_move).setTitle( + inOutbox && (message.ui_snoozed != null || message.error != null) + ? R.string.title_folder_drafts : R.string.title_move); + + bnvActions.getMenu().findItem(R.id.action_archive).setVisible(message.uid != null && !inArchive && hasArchive); + bnvActions.getMenu().findItem(R.id.action_reply).setEnabled(message.content); + bnvActions.getMenu().findItem(R.id.action_reply).setVisible(!inOutbox); + } + + @Override + protected void onException(Bundle args, Throwable ex) { + Helper.unexpectedError(context, owner, ex); + } + }.execute(context, owner, sargs, "message:actions"); + + // Message text + Spanned body = properties.getBody(message.id); + tvBody.setText(body); + tvBody.setMovementMethod(null); + if (internet || message.content) + pbBody.setVisibility(View.VISIBLE); + else + tvNoInternetBody.setVisibility(View.VISIBLE); + + if (body == null && message.content) + if (show_html) + onShowHtmlConfirmed(message); + else { + Bundle args = new Bundle(); + args.putSerializable("message", message); + bodyTask.execute(context, owner, args, "message:body"); + } } void unbind() { @@ -1118,7 +1160,7 @@ public class AdapterMessage extends RecyclerView.Adapter + + Show identicons Show message preview Show address details by default + Automatically show original message for known contacts Automatically show images for known contacts Conversation action bar