Loading k9mail/src/main/java/com/fsck/k9/fragment/MLFProjectionInfo.java 0 → 100644 +60 −0 Original line number Diff line number Diff line package com.fsck.k9.fragment; import java.util.Arrays; import com.fsck.k9.provider.EmailProvider.MessageColumns; import com.fsck.k9.provider.EmailProvider.SpecialColumns; import com.fsck.k9.provider.EmailProvider.ThreadColumns; public final class MLFProjectionInfo { static final String[] THREADED_PROJECTION = { MessageColumns.ID, MessageColumns.UID, MessageColumns.INTERNAL_DATE, MessageColumns.SUBJECT, MessageColumns.DATE, MessageColumns.SENDER_LIST, MessageColumns.TO_LIST, MessageColumns.CC_LIST, MessageColumns.READ, MessageColumns.FLAGGED, MessageColumns.ANSWERED, MessageColumns.FORWARDED, MessageColumns.ATTACHMENT_COUNT, MessageColumns.FOLDER_ID, MessageColumns.PREVIEW_TYPE, MessageColumns.PREVIEW, ThreadColumns.ROOT, SpecialColumns.ACCOUNT_UUID, SpecialColumns.FOLDER_NAME, SpecialColumns.THREAD_COUNT, }; static final int ID_COLUMN = 0; static final int UID_COLUMN = 1; static final int INTERNAL_DATE_COLUMN = 2; static final int SUBJECT_COLUMN = 3; static final int DATE_COLUMN = 4; static final int SENDER_LIST_COLUMN = 5; static final int TO_LIST_COLUMN = 6; static final int CC_LIST_COLUMN = 7; static final int READ_COLUMN = 8; static final int FLAGGED_COLUMN = 9; static final int ANSWERED_COLUMN = 10; static final int FORWARDED_COLUMN = 11; static final int ATTACHMENT_COUNT_COLUMN = 12; static final int FOLDER_ID_COLUMN = 13; static final int PREVIEW_TYPE_COLUMN = 14; static final int PREVIEW_COLUMN = 15; static final int THREAD_ROOT_COLUMN = 16; static final int ACCOUNT_UUID_COLUMN = 17; static final int FOLDER_NAME_COLUMN = 18; static final int THREAD_COUNT_COLUMN = 19; static final String[] PROJECTION = Arrays.copyOf(THREADED_PROJECTION, THREAD_COUNT_COLUMN); } k9mail/src/main/java/com/fsck/k9/fragment/MessageListAdapter.java 0 → 100644 +370 −0 Original line number Diff line number Diff line package com.fsck.k9.fragment; import android.content.Context; import android.database.Cursor; import android.graphics.Color; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.format.DateUtils; import android.text.style.AbsoluteSizeSpan; import android.text.style.ForegroundColorSpan; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.CursorAdapter; import android.widget.TextView; import com.fsck.k9.Account; import com.fsck.k9.FontSizes; import com.fsck.k9.K9; import com.fsck.k9.R; import com.fsck.k9.helper.Utility; import com.fsck.k9.mail.Address; import com.fsck.k9.mailstore.DatabasePreviewType; import com.fsck.k9.ui.ContactBadge; import static com.fsck.k9.fragment.MLFProjectionInfo.ANSWERED_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.ATTACHMENT_COUNT_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.CC_LIST_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.DATE_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.FLAGGED_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.FOLDER_NAME_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.FORWARDED_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.PREVIEW_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.PREVIEW_TYPE_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.READ_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.SENDER_LIST_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.SUBJECT_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.THREAD_COUNT_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.TO_LIST_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.UID_COLUMN; public class MessageListAdapter extends CursorAdapter { private final MessageListFragment fragment; private Drawable mAttachmentIcon; private Drawable mForwardedIcon; private Drawable mAnsweredIcon; private Drawable mForwardedAnsweredIcon; private FontSizes fontSizes = K9.getFontSizes(); MessageListAdapter(MessageListFragment fragment) { super(fragment.getActivity(), null, 0); this.fragment = fragment; mAttachmentIcon = fragment.getResources().getDrawable(R.drawable.ic_email_attachment_small); mAnsweredIcon = fragment.getResources().getDrawable(R.drawable.ic_email_answered_small); mForwardedIcon = fragment.getResources().getDrawable(R.drawable.ic_email_forwarded_small); mForwardedAnsweredIcon = fragment.getResources().getDrawable(R.drawable.ic_email_forwarded_answered_small); } private String recipientSigil(boolean toMe, boolean ccMe) { if (toMe) { return fragment.getString(R.string.messagelist_sent_to_me_sigil); } else if (ccMe) { return fragment.getString(R.string.messagelist_sent_cc_me_sigil); } else { return ""; } } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { View view = fragment.getLayoutInflater().inflate(R.layout.message_list_item, parent, false); MessageViewHolder holder = new MessageViewHolder(fragment); holder.date = (TextView) view.findViewById(R.id.date); holder.chip = view.findViewById(R.id.chip); if (fragment.previewLines == 0 && fragment.contactsPictureLoader == null) { view.findViewById(R.id.preview).setVisibility(View.GONE); holder.preview = (TextView) view.findViewById(R.id.sender_compact); holder.flagged = (CheckBox) view.findViewById(R.id.flagged_center_right); view.findViewById(R.id.flagged_bottom_right).setVisibility(View.GONE); } else { view.findViewById(R.id.sender_compact).setVisibility(View.GONE); holder.preview = (TextView) view.findViewById(R.id.preview); holder.flagged = (CheckBox) view.findViewById(R.id.flagged_bottom_right); view.findViewById(R.id.flagged_center_right).setVisibility(View.GONE); } ContactBadge contactBadge = (ContactBadge) view.findViewById(R.id.contact_badge); if (fragment.contactsPictureLoader != null) { holder.contactBadge = contactBadge; } else { contactBadge.setVisibility(View.GONE); } if (fragment.senderAboveSubject) { holder.from = (TextView) view.findViewById(R.id.subject); fontSizes.setViewTextSize(holder.from, fontSizes.getMessageListSender()); } else { holder.subject = (TextView) view.findViewById(R.id.subject); fontSizes.setViewTextSize(holder.subject, fontSizes.getMessageListSubject()); } fontSizes.setViewTextSize(holder.date, fontSizes.getMessageListDate()); // 1 preview line is needed even if it is set to 0, because subject is part of the same text view holder.preview.setLines(Math.max(fragment.previewLines,1)); fontSizes.setViewTextSize(holder.preview, fontSizes.getMessageListPreview()); holder.threadCount = (TextView) view.findViewById(R.id.thread_count); fontSizes.setViewTextSize(holder.threadCount, fontSizes.getMessageListSubject()); // thread count is next to subject view.findViewById(R.id.selected_checkbox_wrapper).setVisibility((fragment.checkboxes) ? View.VISIBLE : View.GONE); holder.flagged.setVisibility(fragment.stars ? View.VISIBLE : View.GONE); holder.flagged.setOnClickListener(holder); holder.selected = (CheckBox) view.findViewById(R.id.selected_checkbox); holder.selected.setOnClickListener(holder); view.setTag(holder); return view; } @Override public void bindView(View view, Context context, Cursor cursor) { Account account = fragment.getAccountFromCursor(cursor); String fromList = cursor.getString(SENDER_LIST_COLUMN); String toList = cursor.getString(TO_LIST_COLUMN); String ccList = cursor.getString(CC_LIST_COLUMN); Address[] fromAddrs = Address.unpack(fromList); Address[] toAddrs = Address.unpack(toList); Address[] ccAddrs = Address.unpack(ccList); boolean fromMe = fragment.messageHelper.toMe(account, fromAddrs); boolean toMe = fragment.messageHelper.toMe(account, toAddrs); boolean ccMe = fragment.messageHelper.toMe(account, ccAddrs); CharSequence displayName = fragment.messageHelper.getDisplayName(account, fromAddrs, toAddrs); CharSequence displayDate = DateUtils.getRelativeTimeSpanString(context, cursor.getLong(DATE_COLUMN)); Address counterpartyAddress = fetchCounterPartyAddress(fromMe, toAddrs, ccAddrs, fromAddrs); int threadCount = (fragment.showingThreadedList) ? cursor.getInt(THREAD_COUNT_COLUMN) : 0; String subject = MlfUtils.buildSubject(cursor.getString(SUBJECT_COLUMN), fragment.getString(R.string.general_no_subject), threadCount); boolean read = (cursor.getInt(READ_COLUMN) == 1); boolean flagged = (cursor.getInt(FLAGGED_COLUMN) == 1); boolean answered = (cursor.getInt(ANSWERED_COLUMN) == 1); boolean forwarded = (cursor.getInt(FORWARDED_COLUMN) == 1); boolean hasAttachments = (cursor.getInt(ATTACHMENT_COUNT_COLUMN) > 0); MessageViewHolder holder = (MessageViewHolder) view.getTag(); int maybeBoldTypeface = (read) ? Typeface.NORMAL : Typeface.BOLD; long uniqueId = cursor.getLong(fragment.uniqueIdColumn); boolean selected = fragment.selected.contains(uniqueId); holder.chip.setBackgroundColor(account.getChipColor()); if (fragment.checkboxes) { holder.selected.setChecked(selected); } if (fragment.stars) { holder.flagged.setChecked(flagged); } holder.position = cursor.getPosition(); if (holder.contactBadge != null) { updateContactBadge(holder, counterpartyAddress); } setBackgroundColor(view, selected, read); if (fragment.activeMessage != null) { changeBackgroundColorIfActiveMessage(cursor, account, view); } updateWithThreadCount(holder, threadCount); CharSequence beforePreviewText = (fragment.senderAboveSubject) ? subject : displayName; String sigil = recipientSigil(toMe, ccMe); SpannableStringBuilder messageStringBuilder = new SpannableStringBuilder(sigil) .append(beforePreviewText); if (fragment.previewLines > 0) { String preview = getPreview(cursor); messageStringBuilder.append(" ").append(preview); } holder.preview.setText(messageStringBuilder, TextView.BufferType.SPANNABLE); formatPreviewText(holder.preview, beforePreviewText, sigil); Drawable statusHolder = buildStatusHolder(forwarded, answered); if (holder.from != null ) { holder.from.setTypeface(Typeface.create(holder.from.getTypeface(), maybeBoldTypeface)); if (fragment.senderAboveSubject) { holder.from.setCompoundDrawablesWithIntrinsicBounds( statusHolder, // left null, // top hasAttachments ? mAttachmentIcon : null, // right null); // bottom holder.from.setText(displayName); } else { holder.from.setText(new SpannableStringBuilder(sigil).append(displayName)); } } if (holder.subject != null ) { if (!fragment.senderAboveSubject) { holder.subject.setCompoundDrawablesWithIntrinsicBounds( statusHolder, // left null, // top hasAttachments ? mAttachmentIcon : null, // right null); // bottom } holder.subject.setTypeface(Typeface.create(holder.subject.getTypeface(), maybeBoldTypeface)); holder.subject.setText(subject); } holder.date.setText(displayDate); } private void formatPreviewText(TextView preview, CharSequence beforePreviewText, String sigil) { Spannable previewText = (Spannable)preview.getText(); previewText.setSpan(buildSenderSpan(), 0, beforePreviewText.length() + sigil.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); int previewSpanColor = buildPreviewSpanColor(); // Set span (color) for preview message previewText.setSpan(new ForegroundColorSpan(previewSpanColor), beforePreviewText.length() + sigil.length(), previewText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } /** * Create a span section for the sender, and assign the correct font size and weight */ private AbsoluteSizeSpan buildSenderSpan() { int fontSize = (fragment.senderAboveSubject) ? fontSizes.getMessageListSubject(): fontSizes.getMessageListSender(); return new AbsoluteSizeSpan(fontSize, true); } private Address fetchCounterPartyAddress(boolean fromMe, Address[] toAddrs, Address[] ccAddrs, Address[] fromAddrs) { if (fromMe) { if (toAddrs.length > 0) { return toAddrs[0]; } else if (ccAddrs.length > 0) { return ccAddrs[0]; } } else if (fromAddrs.length > 0) { return fromAddrs[0]; } return null; } private void updateContactBadge(MessageViewHolder holder, Address counterpartyAddress) { if (counterpartyAddress != null) { Utility.setContactForBadge(holder.contactBadge, counterpartyAddress); /* * At least in Android 2.2 a different background + padding is used when no * email address is available. ListView reuses the views but ContactBadge * doesn't reset the padding, so we do it ourselves. */ holder.contactBadge.setPadding(0, 0, 0, 0); fragment.contactsPictureLoader.loadContactPicture(counterpartyAddress, holder.contactBadge); } else { holder.contactBadge.assignContactUri(null); holder.contactBadge.setImageResource(R.drawable.ic_contact_picture); } } private void changeBackgroundColorIfActiveMessage(Cursor cursor, Account account, View view) { String uid = cursor.getString(UID_COLUMN); String folderName = cursor.getString(FOLDER_NAME_COLUMN); if (account.getUuid().equals(fragment.activeMessage.getAccountUuid()) && folderName.equals(fragment.activeMessage.getFolderName()) && uid.equals(fragment.activeMessage.getUid())) { int res = R.attr.messageListActiveItemBackgroundColor; TypedValue outValue = new TypedValue(); fragment.getActivity().getTheme().resolveAttribute(res, outValue, true); view.setBackgroundColor(outValue.data); } } private int buildPreviewSpanColor() { //TODO: make this part of the theme return (K9.getK9Theme() == K9.Theme.LIGHT) ? Color.rgb(105, 105, 105) : Color.rgb(160, 160, 160); } private Drawable buildStatusHolder(boolean forwarded, boolean answered) { if (forwarded && answered) { return mForwardedAnsweredIcon; } else if (answered) { return mAnsweredIcon; } else if (forwarded) { return mForwardedIcon; } return null; } private void setBackgroundColor(View view, boolean selected, boolean read) { if (selected || K9.useBackgroundAsUnreadIndicator()) { int res; if (selected) { res = R.attr.messageListSelectedBackgroundColor; } else if (read) { res = R.attr.messageListReadItemBackgroundColor; } else { res = R.attr.messageListUnreadItemBackgroundColor; } TypedValue outValue = new TypedValue(); fragment.getActivity().getTheme().resolveAttribute(res, outValue, true); view.setBackgroundColor(outValue.data); } else { view.setBackgroundColor(Color.TRANSPARENT); } } private void updateWithThreadCount(MessageViewHolder holder, int threadCount) { if (threadCount > 1) { holder.threadCount.setText(String.format("%d", threadCount)); holder.threadCount.setVisibility(View.VISIBLE); } else { holder.threadCount.setVisibility(View.GONE); } } private String getPreview(Cursor cursor) { String previewTypeString = cursor.getString(PREVIEW_TYPE_COLUMN); DatabasePreviewType previewType = DatabasePreviewType.fromDatabaseValue(previewTypeString); switch (previewType) { case NONE: case ERROR: { return ""; } case ENCRYPTED: { return fragment.getString(R.string.preview_encrypted); } case TEXT: { return cursor.getString(PREVIEW_COLUMN); } } throw new AssertionError("Unknown preview type: " + previewType); } } Loading
k9mail/src/main/java/com/fsck/k9/fragment/MLFProjectionInfo.java 0 → 100644 +60 −0 Original line number Diff line number Diff line package com.fsck.k9.fragment; import java.util.Arrays; import com.fsck.k9.provider.EmailProvider.MessageColumns; import com.fsck.k9.provider.EmailProvider.SpecialColumns; import com.fsck.k9.provider.EmailProvider.ThreadColumns; public final class MLFProjectionInfo { static final String[] THREADED_PROJECTION = { MessageColumns.ID, MessageColumns.UID, MessageColumns.INTERNAL_DATE, MessageColumns.SUBJECT, MessageColumns.DATE, MessageColumns.SENDER_LIST, MessageColumns.TO_LIST, MessageColumns.CC_LIST, MessageColumns.READ, MessageColumns.FLAGGED, MessageColumns.ANSWERED, MessageColumns.FORWARDED, MessageColumns.ATTACHMENT_COUNT, MessageColumns.FOLDER_ID, MessageColumns.PREVIEW_TYPE, MessageColumns.PREVIEW, ThreadColumns.ROOT, SpecialColumns.ACCOUNT_UUID, SpecialColumns.FOLDER_NAME, SpecialColumns.THREAD_COUNT, }; static final int ID_COLUMN = 0; static final int UID_COLUMN = 1; static final int INTERNAL_DATE_COLUMN = 2; static final int SUBJECT_COLUMN = 3; static final int DATE_COLUMN = 4; static final int SENDER_LIST_COLUMN = 5; static final int TO_LIST_COLUMN = 6; static final int CC_LIST_COLUMN = 7; static final int READ_COLUMN = 8; static final int FLAGGED_COLUMN = 9; static final int ANSWERED_COLUMN = 10; static final int FORWARDED_COLUMN = 11; static final int ATTACHMENT_COUNT_COLUMN = 12; static final int FOLDER_ID_COLUMN = 13; static final int PREVIEW_TYPE_COLUMN = 14; static final int PREVIEW_COLUMN = 15; static final int THREAD_ROOT_COLUMN = 16; static final int ACCOUNT_UUID_COLUMN = 17; static final int FOLDER_NAME_COLUMN = 18; static final int THREAD_COUNT_COLUMN = 19; static final String[] PROJECTION = Arrays.copyOf(THREADED_PROJECTION, THREAD_COUNT_COLUMN); }
k9mail/src/main/java/com/fsck/k9/fragment/MessageListAdapter.java 0 → 100644 +370 −0 Original line number Diff line number Diff line package com.fsck.k9.fragment; import android.content.Context; import android.database.Cursor; import android.graphics.Color; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.format.DateUtils; import android.text.style.AbsoluteSizeSpan; import android.text.style.ForegroundColorSpan; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.CursorAdapter; import android.widget.TextView; import com.fsck.k9.Account; import com.fsck.k9.FontSizes; import com.fsck.k9.K9; import com.fsck.k9.R; import com.fsck.k9.helper.Utility; import com.fsck.k9.mail.Address; import com.fsck.k9.mailstore.DatabasePreviewType; import com.fsck.k9.ui.ContactBadge; import static com.fsck.k9.fragment.MLFProjectionInfo.ANSWERED_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.ATTACHMENT_COUNT_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.CC_LIST_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.DATE_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.FLAGGED_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.FOLDER_NAME_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.FORWARDED_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.PREVIEW_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.PREVIEW_TYPE_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.READ_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.SENDER_LIST_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.SUBJECT_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.THREAD_COUNT_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.TO_LIST_COLUMN; import static com.fsck.k9.fragment.MLFProjectionInfo.UID_COLUMN; public class MessageListAdapter extends CursorAdapter { private final MessageListFragment fragment; private Drawable mAttachmentIcon; private Drawable mForwardedIcon; private Drawable mAnsweredIcon; private Drawable mForwardedAnsweredIcon; private FontSizes fontSizes = K9.getFontSizes(); MessageListAdapter(MessageListFragment fragment) { super(fragment.getActivity(), null, 0); this.fragment = fragment; mAttachmentIcon = fragment.getResources().getDrawable(R.drawable.ic_email_attachment_small); mAnsweredIcon = fragment.getResources().getDrawable(R.drawable.ic_email_answered_small); mForwardedIcon = fragment.getResources().getDrawable(R.drawable.ic_email_forwarded_small); mForwardedAnsweredIcon = fragment.getResources().getDrawable(R.drawable.ic_email_forwarded_answered_small); } private String recipientSigil(boolean toMe, boolean ccMe) { if (toMe) { return fragment.getString(R.string.messagelist_sent_to_me_sigil); } else if (ccMe) { return fragment.getString(R.string.messagelist_sent_cc_me_sigil); } else { return ""; } } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { View view = fragment.getLayoutInflater().inflate(R.layout.message_list_item, parent, false); MessageViewHolder holder = new MessageViewHolder(fragment); holder.date = (TextView) view.findViewById(R.id.date); holder.chip = view.findViewById(R.id.chip); if (fragment.previewLines == 0 && fragment.contactsPictureLoader == null) { view.findViewById(R.id.preview).setVisibility(View.GONE); holder.preview = (TextView) view.findViewById(R.id.sender_compact); holder.flagged = (CheckBox) view.findViewById(R.id.flagged_center_right); view.findViewById(R.id.flagged_bottom_right).setVisibility(View.GONE); } else { view.findViewById(R.id.sender_compact).setVisibility(View.GONE); holder.preview = (TextView) view.findViewById(R.id.preview); holder.flagged = (CheckBox) view.findViewById(R.id.flagged_bottom_right); view.findViewById(R.id.flagged_center_right).setVisibility(View.GONE); } ContactBadge contactBadge = (ContactBadge) view.findViewById(R.id.contact_badge); if (fragment.contactsPictureLoader != null) { holder.contactBadge = contactBadge; } else { contactBadge.setVisibility(View.GONE); } if (fragment.senderAboveSubject) { holder.from = (TextView) view.findViewById(R.id.subject); fontSizes.setViewTextSize(holder.from, fontSizes.getMessageListSender()); } else { holder.subject = (TextView) view.findViewById(R.id.subject); fontSizes.setViewTextSize(holder.subject, fontSizes.getMessageListSubject()); } fontSizes.setViewTextSize(holder.date, fontSizes.getMessageListDate()); // 1 preview line is needed even if it is set to 0, because subject is part of the same text view holder.preview.setLines(Math.max(fragment.previewLines,1)); fontSizes.setViewTextSize(holder.preview, fontSizes.getMessageListPreview()); holder.threadCount = (TextView) view.findViewById(R.id.thread_count); fontSizes.setViewTextSize(holder.threadCount, fontSizes.getMessageListSubject()); // thread count is next to subject view.findViewById(R.id.selected_checkbox_wrapper).setVisibility((fragment.checkboxes) ? View.VISIBLE : View.GONE); holder.flagged.setVisibility(fragment.stars ? View.VISIBLE : View.GONE); holder.flagged.setOnClickListener(holder); holder.selected = (CheckBox) view.findViewById(R.id.selected_checkbox); holder.selected.setOnClickListener(holder); view.setTag(holder); return view; } @Override public void bindView(View view, Context context, Cursor cursor) { Account account = fragment.getAccountFromCursor(cursor); String fromList = cursor.getString(SENDER_LIST_COLUMN); String toList = cursor.getString(TO_LIST_COLUMN); String ccList = cursor.getString(CC_LIST_COLUMN); Address[] fromAddrs = Address.unpack(fromList); Address[] toAddrs = Address.unpack(toList); Address[] ccAddrs = Address.unpack(ccList); boolean fromMe = fragment.messageHelper.toMe(account, fromAddrs); boolean toMe = fragment.messageHelper.toMe(account, toAddrs); boolean ccMe = fragment.messageHelper.toMe(account, ccAddrs); CharSequence displayName = fragment.messageHelper.getDisplayName(account, fromAddrs, toAddrs); CharSequence displayDate = DateUtils.getRelativeTimeSpanString(context, cursor.getLong(DATE_COLUMN)); Address counterpartyAddress = fetchCounterPartyAddress(fromMe, toAddrs, ccAddrs, fromAddrs); int threadCount = (fragment.showingThreadedList) ? cursor.getInt(THREAD_COUNT_COLUMN) : 0; String subject = MlfUtils.buildSubject(cursor.getString(SUBJECT_COLUMN), fragment.getString(R.string.general_no_subject), threadCount); boolean read = (cursor.getInt(READ_COLUMN) == 1); boolean flagged = (cursor.getInt(FLAGGED_COLUMN) == 1); boolean answered = (cursor.getInt(ANSWERED_COLUMN) == 1); boolean forwarded = (cursor.getInt(FORWARDED_COLUMN) == 1); boolean hasAttachments = (cursor.getInt(ATTACHMENT_COUNT_COLUMN) > 0); MessageViewHolder holder = (MessageViewHolder) view.getTag(); int maybeBoldTypeface = (read) ? Typeface.NORMAL : Typeface.BOLD; long uniqueId = cursor.getLong(fragment.uniqueIdColumn); boolean selected = fragment.selected.contains(uniqueId); holder.chip.setBackgroundColor(account.getChipColor()); if (fragment.checkboxes) { holder.selected.setChecked(selected); } if (fragment.stars) { holder.flagged.setChecked(flagged); } holder.position = cursor.getPosition(); if (holder.contactBadge != null) { updateContactBadge(holder, counterpartyAddress); } setBackgroundColor(view, selected, read); if (fragment.activeMessage != null) { changeBackgroundColorIfActiveMessage(cursor, account, view); } updateWithThreadCount(holder, threadCount); CharSequence beforePreviewText = (fragment.senderAboveSubject) ? subject : displayName; String sigil = recipientSigil(toMe, ccMe); SpannableStringBuilder messageStringBuilder = new SpannableStringBuilder(sigil) .append(beforePreviewText); if (fragment.previewLines > 0) { String preview = getPreview(cursor); messageStringBuilder.append(" ").append(preview); } holder.preview.setText(messageStringBuilder, TextView.BufferType.SPANNABLE); formatPreviewText(holder.preview, beforePreviewText, sigil); Drawable statusHolder = buildStatusHolder(forwarded, answered); if (holder.from != null ) { holder.from.setTypeface(Typeface.create(holder.from.getTypeface(), maybeBoldTypeface)); if (fragment.senderAboveSubject) { holder.from.setCompoundDrawablesWithIntrinsicBounds( statusHolder, // left null, // top hasAttachments ? mAttachmentIcon : null, // right null); // bottom holder.from.setText(displayName); } else { holder.from.setText(new SpannableStringBuilder(sigil).append(displayName)); } } if (holder.subject != null ) { if (!fragment.senderAboveSubject) { holder.subject.setCompoundDrawablesWithIntrinsicBounds( statusHolder, // left null, // top hasAttachments ? mAttachmentIcon : null, // right null); // bottom } holder.subject.setTypeface(Typeface.create(holder.subject.getTypeface(), maybeBoldTypeface)); holder.subject.setText(subject); } holder.date.setText(displayDate); } private void formatPreviewText(TextView preview, CharSequence beforePreviewText, String sigil) { Spannable previewText = (Spannable)preview.getText(); previewText.setSpan(buildSenderSpan(), 0, beforePreviewText.length() + sigil.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); int previewSpanColor = buildPreviewSpanColor(); // Set span (color) for preview message previewText.setSpan(new ForegroundColorSpan(previewSpanColor), beforePreviewText.length() + sigil.length(), previewText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } /** * Create a span section for the sender, and assign the correct font size and weight */ private AbsoluteSizeSpan buildSenderSpan() { int fontSize = (fragment.senderAboveSubject) ? fontSizes.getMessageListSubject(): fontSizes.getMessageListSender(); return new AbsoluteSizeSpan(fontSize, true); } private Address fetchCounterPartyAddress(boolean fromMe, Address[] toAddrs, Address[] ccAddrs, Address[] fromAddrs) { if (fromMe) { if (toAddrs.length > 0) { return toAddrs[0]; } else if (ccAddrs.length > 0) { return ccAddrs[0]; } } else if (fromAddrs.length > 0) { return fromAddrs[0]; } return null; } private void updateContactBadge(MessageViewHolder holder, Address counterpartyAddress) { if (counterpartyAddress != null) { Utility.setContactForBadge(holder.contactBadge, counterpartyAddress); /* * At least in Android 2.2 a different background + padding is used when no * email address is available. ListView reuses the views but ContactBadge * doesn't reset the padding, so we do it ourselves. */ holder.contactBadge.setPadding(0, 0, 0, 0); fragment.contactsPictureLoader.loadContactPicture(counterpartyAddress, holder.contactBadge); } else { holder.contactBadge.assignContactUri(null); holder.contactBadge.setImageResource(R.drawable.ic_contact_picture); } } private void changeBackgroundColorIfActiveMessage(Cursor cursor, Account account, View view) { String uid = cursor.getString(UID_COLUMN); String folderName = cursor.getString(FOLDER_NAME_COLUMN); if (account.getUuid().equals(fragment.activeMessage.getAccountUuid()) && folderName.equals(fragment.activeMessage.getFolderName()) && uid.equals(fragment.activeMessage.getUid())) { int res = R.attr.messageListActiveItemBackgroundColor; TypedValue outValue = new TypedValue(); fragment.getActivity().getTheme().resolveAttribute(res, outValue, true); view.setBackgroundColor(outValue.data); } } private int buildPreviewSpanColor() { //TODO: make this part of the theme return (K9.getK9Theme() == K9.Theme.LIGHT) ? Color.rgb(105, 105, 105) : Color.rgb(160, 160, 160); } private Drawable buildStatusHolder(boolean forwarded, boolean answered) { if (forwarded && answered) { return mForwardedAnsweredIcon; } else if (answered) { return mAnsweredIcon; } else if (forwarded) { return mForwardedIcon; } return null; } private void setBackgroundColor(View view, boolean selected, boolean read) { if (selected || K9.useBackgroundAsUnreadIndicator()) { int res; if (selected) { res = R.attr.messageListSelectedBackgroundColor; } else if (read) { res = R.attr.messageListReadItemBackgroundColor; } else { res = R.attr.messageListUnreadItemBackgroundColor; } TypedValue outValue = new TypedValue(); fragment.getActivity().getTheme().resolveAttribute(res, outValue, true); view.setBackgroundColor(outValue.data); } else { view.setBackgroundColor(Color.TRANSPARENT); } } private void updateWithThreadCount(MessageViewHolder holder, int threadCount) { if (threadCount > 1) { holder.threadCount.setText(String.format("%d", threadCount)); holder.threadCount.setVisibility(View.VISIBLE); } else { holder.threadCount.setVisibility(View.GONE); } } private String getPreview(Cursor cursor) { String previewTypeString = cursor.getString(PREVIEW_TYPE_COLUMN); DatabasePreviewType previewType = DatabasePreviewType.fromDatabaseValue(previewTypeString); switch (previewType) { case NONE: case ERROR: { return ""; } case ENCRYPTED: { return fragment.getString(R.string.preview_encrypted); } case TEXT: { return cursor.getString(PREVIEW_COLUMN); } } throw new AssertionError("Unknown preview type: " + previewType); } }