New message list formatting per pixel perfects
* Need icon assets (attachment, meeting, star on/off, and checkbox on/off) Change-Id: I6780fb354584ce5ea398b555a8485cf600617586
This commit is contained in:
parent
f946ff0019
commit
06a2f4a3b1
|
@ -23,7 +23,7 @@
|
|||
<!-- XL activity dimensions -->
|
||||
|
||||
<!-- width of mailbox list -->
|
||||
<dimen name="mailbox_list_width">312dip</dimen>
|
||||
<dimen name="mailbox_list_width">304dip</dimen>
|
||||
<!-- width of the message list, on the message list + message view mode. -->
|
||||
<dimen name="message_list_width">466dip</dimen>
|
||||
</resources>
|
||||
|
|
|
@ -17,14 +17,19 @@
|
|||
<resources>
|
||||
<dimen name="button_minWidth">100sp</dimen>
|
||||
<dimen name="message_list_item_text_size">16dip</dimen>
|
||||
<dimen name="message_list_item_checkbox_hit_width">60dip</dimen>
|
||||
<dimen name="message_list_item_favorite_hit_width">50dip</dimen>
|
||||
<dimen name="message_list_item_checkbox_hit_width">64dip</dimen>
|
||||
<dimen name="message_list_item_favorite_hit_width">64dip</dimen>
|
||||
<dimen name="message_list_item_favorite_padding_right">16dip</dimen>
|
||||
<dimen name="message_list_item_date_icon_width_wide">144dip</dimen>
|
||||
<dimen name="message_list_item_date_icon_width_narrow">112dip</dimen>
|
||||
<dimen name="message_list_item_sender_padding_top_narrow">10dip</dimen>
|
||||
<dimen name="message_list_item_sender_width">200dip</dimen>
|
||||
<dimen name="message_list_item_padding_large">32dip</dimen>
|
||||
<dimen name="message_list_item_padding_medium">6dip</dimen>
|
||||
<dimen name="message_list_item_padding_small">4dip</dimen>
|
||||
<dimen name="message_list_item_padding_very_small">2dip</dimen>
|
||||
<dimen name="message_list_item_minimum_date_width">64dip</dimen>
|
||||
<dimen name="message_list_item_height_wide">64dip</dimen>
|
||||
<dimen name="message_list_item_height_narrow">72dip</dimen>
|
||||
<dimen name="message_list_item_height_narrow">80dip</dimen>
|
||||
<dimen name="message_list_item_minimum_width_wide_mode">720dip</dimen>
|
||||
<dimen name="message_list_item_color_tip_width">35dip</dimen>
|
||||
<dimen name="message_list_item_color_tip_height">8dip</dimen>
|
||||
|
|
|
@ -443,9 +443,9 @@ save attachment.</string>
|
|||
<!-- The label of the previous button on the message view screen. -->
|
||||
<string name="message_view_move_to_older">Older</string>
|
||||
|
||||
<!-- The message snippet, of the form subject + separator + start of text -->
|
||||
<string name="message_list_snippet"><xliff:g id="subject" example="Re: Foo">
|
||||
%1$s</xliff:g> - <xliff:g id="text" example="Hi, John. Blah...">%2$s</xliff:g></string>
|
||||
<!-- A simple divider between subject and message snippet in the message list view
|
||||
[CHAR LIMIT=4]-->
|
||||
<string name="message_list_subject_snippet_divider">\u0020\u2014\u0020</string>
|
||||
|
||||
<!-- Title of screen when setting up new email account [CHAR LIMIT=45] -->
|
||||
<string name="account_setup_basics_title">Account setup</string>
|
||||
|
|
|
@ -28,11 +28,15 @@ import android.graphics.Paint.Align;
|
|||
import android.graphics.Paint.FontMetricsInt;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.Layout.Alignment;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.StaticLayout;
|
||||
import android.text.TextPaint;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextUtils.TruncateAt;
|
||||
import android.text.format.DateUtils;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
@ -88,12 +92,15 @@ public class MessageListItem extends View {
|
|||
private static Bitmap sInviteIcon;
|
||||
private static Bitmap sFavoriteIconOff;
|
||||
private static Bitmap sFavoriteIconOn;
|
||||
private static int sFavoriteIconLeft;
|
||||
private static int sFavoriteIconWidth;
|
||||
private static Bitmap sSelectedIconOn;
|
||||
private static Bitmap sSelectedIconOff;
|
||||
private static String sSubjectSnippetDivider;
|
||||
|
||||
public String mSender;
|
||||
public CharSequence mText;
|
||||
public String mSnippet;
|
||||
public String mSubject;
|
||||
public boolean mRead;
|
||||
public long mTimestamp;
|
||||
public boolean mHasAttachment = false;
|
||||
|
@ -111,8 +118,13 @@ public class MessageListItem extends View {
|
|||
private int mDateFaveWidth;
|
||||
|
||||
private static int sCheckboxHitWidth;
|
||||
private static int sMinimumDateWidth;
|
||||
private static int sDateIconWidthWide;
|
||||
private static int sDateIconWidthNarrow;
|
||||
private static int sFavoriteHitWidth;
|
||||
private static int sFavoritePaddingRight;
|
||||
private static int sSenderPaddingTopNarrow;
|
||||
private static int sSenderWidth;
|
||||
private static int sPaddingLarge;
|
||||
private static int sPaddingVerySmall;
|
||||
private static int sPaddingSmall;
|
||||
private static int sPaddingMedium;
|
||||
|
@ -133,13 +145,23 @@ public class MessageListItem extends View {
|
|||
private void init(Context context) {
|
||||
if (!sInit) {
|
||||
Resources r = context.getResources();
|
||||
|
||||
sSubjectSnippetDivider = r.getString(R.string.message_list_subject_snippet_divider);
|
||||
sCheckboxHitWidth =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_checkbox_hit_width);
|
||||
sFavoriteHitWidth =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_favorite_hit_width);
|
||||
sMinimumDateWidth =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_minimum_date_width);
|
||||
sFavoritePaddingRight =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_favorite_padding_right);
|
||||
sSenderPaddingTopNarrow =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_sender_padding_top_narrow);
|
||||
sDateIconWidthWide =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_date_icon_width_wide);
|
||||
sDateIconWidthNarrow =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_date_icon_width_narrow);
|
||||
sSenderWidth =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_sender_width);
|
||||
sPaddingLarge =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_padding_large);
|
||||
sPaddingMedium =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_padding_medium);
|
||||
sPaddingSmall =
|
||||
|
@ -184,8 +206,7 @@ public class MessageListItem extends View {
|
|||
sSelectedIconOn =
|
||||
BitmapFactory.decodeResource(r, R.drawable.btn_check_on_normal_holo_light);
|
||||
|
||||
sFavoriteIconLeft =
|
||||
sFavoriteHitWidth - ((sFavoriteHitWidth - sFavoriteIconOff.getWidth()) / 2);
|
||||
sFavoriteIconWidth = sFavoriteIconOff.getWidth();
|
||||
sInit = true;
|
||||
}
|
||||
}
|
||||
|
@ -205,27 +226,38 @@ public class MessageListItem extends View {
|
|||
}
|
||||
|
||||
private void calculateDrawingData() {
|
||||
SpannableStringBuilder ssb = new SpannableStringBuilder();
|
||||
boolean hasSubject = false;
|
||||
if (!TextUtils.isEmpty(mSubject)) {
|
||||
SpannableString ss = new SpannableString(mSubject);
|
||||
ss.setSpan(new StyleSpan(mRead ? Typeface.NORMAL : Typeface.BOLD), 0, ss.length(),
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
ssb.append(ss);
|
||||
hasSubject = true;
|
||||
}
|
||||
if (!TextUtils.isEmpty(mSnippet)) {
|
||||
if (hasSubject) {
|
||||
ssb.append(sSubjectSnippetDivider);
|
||||
}
|
||||
ssb.append(mSnippet);
|
||||
}
|
||||
mText = ssb;
|
||||
|
||||
if (mMode == MODE_WIDE) {
|
||||
mDateFaveWidth = sFavoriteHitWidth + sMinimumDateWidth;
|
||||
mDateFaveWidth = sFavoriteHitWidth + sDateIconWidthWide;
|
||||
} else {
|
||||
mDateFaveWidth = sMinimumDateWidth;
|
||||
mDateFaveWidth = sDateIconWidthNarrow;
|
||||
}
|
||||
mSenderSnippetWidth = mViewWidth - mDateFaveWidth - sCheckboxHitWidth;
|
||||
|
||||
// In wide mode, we use 3/4 for snippet and 1/4 for sender
|
||||
mSnippetWidth = mSenderSnippetWidth;
|
||||
if (mMode == MODE_WIDE) {
|
||||
mSnippetWidth = mSenderSnippetWidth * 3 / 4;
|
||||
}
|
||||
if (mHasAttachment) {
|
||||
mSnippetWidth -= (sAttachmentIcon.getWidth() + sPaddingSmall);
|
||||
}
|
||||
if (mHasInvite) {
|
||||
mSnippetWidth -= (sInviteIcon.getWidth() + sPaddingSmall);
|
||||
mSnippetWidth = mSenderSnippetWidth - sSenderWidth - sPaddingLarge;
|
||||
}
|
||||
|
||||
// First, we create a StaticLayout with our snippet to get the line breaks
|
||||
StaticLayout layout = new StaticLayout(mSnippet, 0, mSnippet.length(), sDefaultPaint,
|
||||
// Create a StaticLayout with our snippet to get the line breaks
|
||||
StaticLayout layout = new StaticLayout(mText, 0, mText.length(), sDefaultPaint,
|
||||
mSnippetWidth, Alignment.ALIGN_NORMAL, 1, 0, true);
|
||||
// Get the number of lines needed to render the whole snippet
|
||||
mSnippetLineCount = layout.getLineCount();
|
||||
|
@ -234,26 +266,26 @@ public class MessageListItem extends View {
|
|||
for (int i = 0; i < MAX_SUBJECT_SNIPPET_LINES; i++) {
|
||||
int start = layout.getLineStart(i);
|
||||
if (i == MAX_SUBJECT_SNIPPET_LINES - 1) {
|
||||
int end = mText.length() - 1;
|
||||
if (start > end) continue;
|
||||
// For the final line, ellipsize the text to our width
|
||||
mSnippetLines[i] = TextUtils.ellipsize(mSnippet.substring(start), sDefaultPaint,
|
||||
mSnippetLines[i] = TextUtils.ellipsize(mText.subSequence(start, end), sDefaultPaint,
|
||||
mSnippetWidth, TruncateAt.END);
|
||||
} else {
|
||||
// Just extract from start to end
|
||||
mSnippetLines[i] = mSnippet.substring(start, layout.getLineEnd(i));
|
||||
mSnippetLines[i] = mText.subSequence(start, layout.getLineEnd(i));
|
||||
}
|
||||
}
|
||||
|
||||
// Now, format the sender for its width
|
||||
TextPaint senderPaint = mRead ? sDefaultPaint : sBoldPaint;
|
||||
// In wide mode, we use 1/4 of the width, otherwise, the whole width
|
||||
int senderWidth = (mMode == MODE_WIDE) ? mSenderSnippetWidth / 4 : mSenderSnippetWidth;
|
||||
int senderWidth = (mMode == MODE_WIDE) ? sSenderWidth : mSenderSnippetWidth;
|
||||
// And get the ellipsized string for the calculated width
|
||||
mFormattedSender = TextUtils.ellipsize(mSender, senderPaint, senderWidth - sPaddingMedium,
|
||||
TruncateAt.END);
|
||||
mFormattedSender = TextUtils.ellipsize(mSender, senderPaint, senderWidth, TruncateAt.END);
|
||||
// Get a nicely formatted date string (relative to today)
|
||||
String date = DateUtils.getRelativeTimeSpanString(getContext(), mTimestamp).toString();
|
||||
// And make it fit to our size
|
||||
mFormattedDate = TextUtils.ellipsize(date, sDatePaint, sMinimumDateWidth, TruncateAt.END);
|
||||
mFormattedDate = TextUtils.ellipsize(date, sDatePaint, sDateIconWidthWide, TruncateAt.END);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -317,13 +349,13 @@ public class MessageListItem extends View {
|
|||
int senderY;
|
||||
|
||||
if (mMode == MODE_WIDE) {
|
||||
// In wide mode, we'll use 1/4 for sender and 3/4 for snippet
|
||||
snippetX += mSenderSnippetWidth / 4;
|
||||
// Get the right starting point for the snippet
|
||||
snippetX += sSenderWidth + sPaddingLarge;
|
||||
// And center the sender and snippet
|
||||
senderY = (mViewHeight - descent - ascent) / 2;
|
||||
snippetY = ((mViewHeight - (2 * lineHeight)) / 2) - ascent;
|
||||
} else {
|
||||
senderY = 20; // TODO Remove magic number
|
||||
senderY = -ascent + sSenderPaddingTopNarrow;
|
||||
snippetY = senderY + lineHeight + sPaddingVerySmall;
|
||||
}
|
||||
|
||||
|
@ -346,19 +378,49 @@ public class MessageListItem extends View {
|
|||
mRead ? sDefaultPaint : sBoldPaint);
|
||||
|
||||
// Draw each of the snippet lines
|
||||
int subjectEnd = (mSubject == null) ? 0 : mSubject.length();
|
||||
int lineStart = 0;
|
||||
TextPaint subjectPaint = mRead ? sDefaultPaint : sBoldPaint;
|
||||
for (int i = 0; i < MAX_SUBJECT_SNIPPET_LINES; i++) {
|
||||
CharSequence line = mSnippetLines[i];
|
||||
int drawX = snippetX;
|
||||
if (line != null) {
|
||||
canvas.drawText(line, 0, line.length(), snippetX, snippetY, sDefaultPaint);
|
||||
int defaultPaintStart = 0;
|
||||
if (lineStart <= subjectEnd) {
|
||||
int boldPaintEnd = subjectEnd - lineStart;
|
||||
if (boldPaintEnd > line.length()) {
|
||||
boldPaintEnd = line.length();
|
||||
}
|
||||
// From 0 to end, do in bold or default depending on the read flag
|
||||
canvas.drawText(line, 0, boldPaintEnd, drawX, snippetY, subjectPaint);
|
||||
defaultPaintStart = boldPaintEnd;
|
||||
drawX += subjectPaint.measureText(line, 0, boldPaintEnd);
|
||||
}
|
||||
canvas.drawText(line, defaultPaintStart, line.length(), drawX, snippetY,
|
||||
sDefaultPaint);
|
||||
snippetY += lineHeight;
|
||||
lineStart += line.length();
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the attachment and invite icons, if necessary
|
||||
int left = mSenderSnippetWidth + sCheckboxHitWidth;
|
||||
int datePaddingRight;
|
||||
if (mMode == MODE_WIDE) {
|
||||
datePaddingRight = sFavoriteHitWidth;
|
||||
} else {
|
||||
datePaddingRight = sPaddingLarge;
|
||||
}
|
||||
int left = mViewWidth - datePaddingRight - (int)sDefaultPaint.measureText(mFormattedDate,
|
||||
0, mFormattedDate.length()) - sPaddingMedium;
|
||||
|
||||
if (mHasAttachment) {
|
||||
left -= sAttachmentIcon.getWidth() + sPaddingSmall;
|
||||
int iconTop = (mViewHeight - sAttachmentIcon.getHeight()) / 2;
|
||||
int iconTop;
|
||||
if (mMode == MODE_WIDE) {
|
||||
iconTop = (mViewHeight - sAttachmentIcon.getHeight()) / 2;
|
||||
} else {
|
||||
iconTop = senderY - sAttachmentIcon.getHeight();
|
||||
}
|
||||
canvas.drawBitmap(sAttachmentIcon, left, iconTop, sDefaultPaint);
|
||||
}
|
||||
if (mHasInvite) {
|
||||
|
@ -368,17 +430,19 @@ public class MessageListItem extends View {
|
|||
}
|
||||
|
||||
// Draw the date
|
||||
int dateRight = mViewWidth - sPaddingMedium;
|
||||
if (mMode == MODE_WIDE) {
|
||||
dateRight -= sFavoriteHitWidth;
|
||||
}
|
||||
canvas.drawText(mFormattedDate, 0, mFormattedDate.length(), dateRight, senderY, sDatePaint);
|
||||
canvas.drawText(mFormattedDate, 0, mFormattedDate.length(), mViewWidth - datePaddingRight,
|
||||
senderY, sDatePaint);
|
||||
|
||||
// Draw the favorite icon
|
||||
int faveLeft = mViewWidth - sFavoriteIconLeft;
|
||||
int faveLeft = mViewWidth - sFavoriteIconWidth;
|
||||
if (mMode == MODE_WIDE) {
|
||||
faveLeft -= sFavoritePaddingRight;
|
||||
} else {
|
||||
faveLeft -= sPaddingLarge;
|
||||
}
|
||||
int faveTop = (mViewHeight - sFavoriteIconOff.getHeight()) / 2;
|
||||
if (mMode == MODE_NARROW) {
|
||||
faveTop += sPaddingMedium;
|
||||
faveTop += sSenderPaddingTopNarrow;
|
||||
}
|
||||
canvas.drawBitmap(mIsFavorite ? sFavoriteIconOn : sFavoriteIconOff, faveLeft, faveTop,
|
||||
sDefaultPaint);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package com.android.email.activity;
|
||||
|
||||
import com.android.email.Email;
|
||||
import com.android.email.R;
|
||||
import com.android.email.ResourceHelper;
|
||||
import com.android.email.Utility;
|
||||
import com.android.email.data.ThrottlingCursorLoader;
|
||||
|
@ -29,7 +28,6 @@ import android.content.Context;
|
|||
import android.content.Loader;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -146,23 +144,10 @@ import java.util.Set;
|
|||
itemView.mTimestamp = cursor.getLong(COLUMN_DATE);
|
||||
itemView.mSender = cursor.getString(COLUMN_DISPLAY_NAME);
|
||||
itemView.mSnippet = cursor.getString(COLUMN_SNIPPET);
|
||||
itemView.mSubject = cursor.getString(COLUMN_SUBJECT);
|
||||
itemView.mSnippetLineCount = MessageListItem.NEEDS_LAYOUT;
|
||||
itemView.mColorChipPaint =
|
||||
mShowColorChips ? mResourceHelper.getAccountColorPaint(accountId) : null;
|
||||
|
||||
String text = cursor.getString(COLUMN_SUBJECT);
|
||||
String snippet = cursor.getString(COLUMN_SNIPPET);
|
||||
if (!TextUtils.isEmpty(snippet)) {
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
text = snippet;
|
||||
} else {
|
||||
text = context.getString(R.string.message_list_snippet, text, snippet);
|
||||
}
|
||||
}
|
||||
if (text == null) {
|
||||
text = "";
|
||||
}
|
||||
itemView.mSnippet = text;
|
||||
mShowColorChips ? mResourceHelper.getAccountColorPaint(accountId) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue