Initial rewrite of MessageListItem for XL
* Drawing all done by MessageListItem, based on view width * Completely functional, layout tweaks required TODO: Consider caching drawing values for performance Bug: 3137994 Change-Id: Ie3de79357bfe976b2fcebdedb71dea011252b445
This commit is contained in:
parent
349055aad4
commit
937ea4fc87
BIN
res/drawable-hdpi/btn_check_off_normal_holo_light.png
Normal file
BIN
res/drawable-hdpi/btn_check_off_normal_holo_light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 267 B |
BIN
res/drawable-hdpi/btn_check_on_normal_holo_light.png
Normal file
BIN
res/drawable-hdpi/btn_check_on_normal_holo_light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 406 B |
BIN
res/drawable-mdpi/btn_check_off_normal_holo_light.png
Normal file
BIN
res/drawable-mdpi/btn_check_off_normal_holo_light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 267 B |
BIN
res/drawable-mdpi/btn_check_on_normal_holo_light.png
Normal file
BIN
res/drawable-mdpi/btn_check_on_normal_holo_light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 406 B |
@ -1,106 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2010 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<!-- xlarge -->
|
||||
|
||||
<!-- extends RelativeLayout -->
|
||||
<com.android.email.activity.MessageListItem
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?android:attr/listPreferredItemHeight"
|
||||
android:background="?android:attr/activatedBackgroundIndicator"
|
||||
>
|
||||
<View
|
||||
android:id="@+id/chip"
|
||||
android:background="@drawable/appointment_indicator_leftside_1"
|
||||
android:layout_width="4dip"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerVertical="true"
|
||||
/>
|
||||
<ImageView
|
||||
android:id="@+id/selected"
|
||||
android:layout_toRightOf="@id/chip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:paddingLeft="24dip"
|
||||
android:paddingRight="24dip"
|
||||
/>
|
||||
<ImageView
|
||||
android:id="@+id/favorite"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:paddingLeft="24dip"
|
||||
android:paddingRight="24dip"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/from"
|
||||
android:layout_toRightOf="@id/selected"
|
||||
android:layout_width="80dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/date"
|
||||
android:layout_toLeftOf="@id/favorite"
|
||||
android:layout_width="80dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="0dip"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
<ImageView
|
||||
android:id="@+id/icon_invite"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toLeftOf="@id/date"
|
||||
android:layout_marginLeft="4dip"
|
||||
android:layout_marginRight="4dip"
|
||||
android:layout_centerVertical="true"
|
||||
android:src="@drawable/ic_calendar_event_small"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
<ImageView
|
||||
android:id="@+id/icon_attachment"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toLeftOf="@id/icon_invite"
|
||||
android:layout_marginLeft="4dip"
|
||||
android:layout_marginRight="4dip"
|
||||
android:layout_centerVertical="true"
|
||||
android:src="@drawable/ic_mms_attachment_small"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/subject"
|
||||
android:layout_toRightOf="@id/from"
|
||||
android:layout_toLeftOf="@id/icon_attachment"
|
||||
android:layout_width="80dip"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="12dip"
|
||||
android:layout_marginTop="12dip"
|
||||
android:layout_marginRight="24dip"
|
||||
android:layout_marginLeft="24dip"
|
||||
android:layout_centerVertical="true"
|
||||
/>
|
||||
</com.android.email.activity.MessageListItem>
|
@ -16,4 +16,14 @@
|
||||
|
||||
<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_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_minimum_width_wide_mode">720dip</dimen>
|
||||
</resources>
|
||||
|
@ -19,47 +19,344 @@ package com.android.email.activity;
|
||||
import com.android.email.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint.Align;
|
||||
import android.graphics.Paint.FontMetricsInt;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.Layout.Alignment;
|
||||
import android.text.StaticLayout;
|
||||
import android.text.TextPaint;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextUtils.TruncateAt;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* This custom View is the list item for the MessageList activity, and serves two purposes:
|
||||
* 1. It's a container to store message metadata (e.g. the ids of the message, mailbox, & account)
|
||||
* 2. It handles internal clicks such as the checkbox or the favorite star
|
||||
*/
|
||||
public class MessageListItem extends RelativeLayout {
|
||||
public class MessageListItem extends View {
|
||||
// Note: messagesAdapter directly fiddles with these fields.
|
||||
/* package */ long mMessageId;
|
||||
/* package */ long mMailboxId;
|
||||
/* package */ long mAccountId;
|
||||
/* package */ boolean mRead;
|
||||
/* package */ boolean mFavorite;
|
||||
|
||||
private MessagesAdapter mAdapter;
|
||||
|
||||
private boolean mDownEvent;
|
||||
private boolean mCachedViewPositions;
|
||||
private int mCheckRight;
|
||||
private int mStarLeft;
|
||||
|
||||
// Padding to increase clickable areas on left & right of each list item
|
||||
private final static float CHECKMARK_PAD = 20.0F;
|
||||
private final static float STAR_PAD = 20.0F;
|
||||
|
||||
public static final String MESSAGE_LIST_ITEMS_CLIP_LABEL =
|
||||
"com.android.email.MESSAGE_LIST_ITEMS";
|
||||
|
||||
public MessageListItem(Context context) {
|
||||
super(context);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public MessageListItem(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public MessageListItem(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init(context);
|
||||
}
|
||||
|
||||
// We always show two lines of subject/snippet
|
||||
private static final int MAX_SUBJECT_SNIPPET_LINES = 2;
|
||||
// Narrow mode shows sender/snippet and time/favorite stacked to save real estate; due to this,
|
||||
// it is also somewhat taller
|
||||
private static final int MODE_NARROW = 1;
|
||||
// Wide mode shows sender, snippet, time, and favorite spread out across the screen
|
||||
private static final int MODE_WIDE = 2;
|
||||
// Sentinel indicating that the view needs layout
|
||||
public static final int NEEDS_LAYOUT = -1;
|
||||
|
||||
private static boolean sInit = false;
|
||||
private static final TextPaint sDefaultPaint = new TextPaint();
|
||||
private static final TextPaint sBoldPaint = new TextPaint();
|
||||
private static final TextPaint sDatePaint = new TextPaint();
|
||||
private static Bitmap sAttachmentIcon;
|
||||
private static Bitmap sInviteIcon;
|
||||
private static Bitmap sFavoriteIconOff;
|
||||
private static Bitmap sFavoriteIconOn;
|
||||
private static int sFavoriteIconLeft;
|
||||
private static Bitmap sSelectedIconOn;
|
||||
private static Bitmap sSelectedIconOff;
|
||||
|
||||
public String mSender;
|
||||
public String mSnippet;
|
||||
public boolean mRead;
|
||||
public long mTimestamp;
|
||||
public boolean mHasAttachment = false;
|
||||
public boolean mHasInvite = true;
|
||||
public boolean mIsFavorite = false;
|
||||
|
||||
private int mMode = -1;
|
||||
|
||||
private int mViewWidth = 0;
|
||||
private int mViewHeight = 0;
|
||||
private int mSenderSnippetWidth;
|
||||
private int mSnippetWidth;
|
||||
private int mDateFaveWidth;
|
||||
|
||||
private static int sCheckboxHitWidth;
|
||||
private static int sMinimumDateWidth;
|
||||
private static int sFavoriteHitWidth;
|
||||
private static int sPaddingVerySmall;
|
||||
private static int sPaddingSmall;
|
||||
private static int sPaddingMedium;
|
||||
private static int sTextSize;
|
||||
private static int sItemHeightWide;
|
||||
private static int sItemHeightNarrow;
|
||||
private static int sMinimumWidthWideMode;
|
||||
|
||||
public int mSnippetLineCount = NEEDS_LAYOUT;
|
||||
private final CharSequence[] mSnippetLines = new CharSequence[MAX_SUBJECT_SNIPPET_LINES];
|
||||
private CharSequence mFormattedSender;
|
||||
private CharSequence mFormattedDate;
|
||||
|
||||
private void init(Context context) {
|
||||
if (!sInit) {
|
||||
Resources r = context.getResources();
|
||||
|
||||
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);
|
||||
sPaddingMedium =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_padding_medium);
|
||||
sPaddingSmall =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_padding_small);
|
||||
sPaddingVerySmall =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_padding_very_small);
|
||||
sTextSize =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_text_size);
|
||||
sItemHeightWide =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_height_wide);
|
||||
sItemHeightNarrow =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_height_narrow);
|
||||
sMinimumWidthWideMode =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_minimum_width_wide_mode);
|
||||
|
||||
sDefaultPaint.setTypeface(Typeface.DEFAULT);
|
||||
sDefaultPaint.setTextSize(sTextSize);
|
||||
sDefaultPaint.setAntiAlias(true);
|
||||
sDatePaint.setTypeface(Typeface.DEFAULT);
|
||||
sDatePaint.setTextSize(sTextSize - 1);
|
||||
sDatePaint.setAntiAlias(true);
|
||||
sDatePaint.setTextAlign(Align.RIGHT);
|
||||
sBoldPaint.setTypeface(Typeface.DEFAULT_BOLD);
|
||||
sBoldPaint.setTextSize(sTextSize);
|
||||
sBoldPaint.setAntiAlias(true);
|
||||
sAttachmentIcon = BitmapFactory.decodeResource(r, R.drawable.ic_mms_attachment_small);
|
||||
sInviteIcon = BitmapFactory.decodeResource(r, R.drawable.ic_calendar_event_small);
|
||||
sFavoriteIconOff =
|
||||
BitmapFactory.decodeResource(r, R.drawable.btn_star_big_buttonless_dark_off);
|
||||
sFavoriteIconOn =
|
||||
BitmapFactory.decodeResource(r, R.drawable.btn_star_big_buttonless_dark_on);
|
||||
sSelectedIconOff =
|
||||
BitmapFactory.decodeResource(r, R.drawable.btn_check_off_normal_holo_light);
|
||||
sSelectedIconOn =
|
||||
BitmapFactory.decodeResource(r, R.drawable.btn_check_on_normal_holo_light);
|
||||
|
||||
sFavoriteIconLeft =
|
||||
sFavoriteHitWidth - ((sFavoriteHitWidth - sFavoriteIconOff.getWidth()) / 2);
|
||||
sInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the mode of this view (WIDE or NORMAL)
|
||||
*
|
||||
* @param width The width of the view
|
||||
* @return The mode of the view
|
||||
*/
|
||||
private int getViewMode(int width) {
|
||||
int mode = MODE_NARROW;
|
||||
if (width > sMinimumWidthWideMode) {
|
||||
mode = MODE_WIDE;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
private void calculateDrawingData() {
|
||||
if (mMode == MODE_WIDE) {
|
||||
mDateFaveWidth = sFavoriteHitWidth + sMinimumDateWidth;
|
||||
} else {
|
||||
mDateFaveWidth = sMinimumDateWidth;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
// First, we create a StaticLayout with our snippet to get the line breaks
|
||||
StaticLayout layout = new StaticLayout(mSnippet, 0, mSnippet.length(), sDefaultPaint,
|
||||
mSnippetWidth, Alignment.ALIGN_NORMAL, 1, 0, true);
|
||||
// Get the number of lines needed to render the whole snippet
|
||||
mSnippetLineCount = layout.getLineCount();
|
||||
// Go through our maximum number of lines, and save away what we'll end up displaying
|
||||
// for those lines
|
||||
for (int i = 0; i < MAX_SUBJECT_SNIPPET_LINES; i++) {
|
||||
int start = layout.getLineStart(i);
|
||||
if (i == MAX_SUBJECT_SNIPPET_LINES - 1) {
|
||||
// For the final line, ellipsize the text to our width
|
||||
mSnippetLines[i] = TextUtils.ellipsize(mSnippet.substring(start), sDefaultPaint,
|
||||
mSnippetWidth, TruncateAt.END);
|
||||
} else {
|
||||
// Just extract from start to end
|
||||
mSnippetLines[i] = mSnippet.substring(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;
|
||||
// And get the ellipsized string for the calculated width
|
||||
mFormattedSender = TextUtils.ellipsize(mSender, senderPaint, senderWidth - sPaddingMedium,
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
mViewWidth = MeasureSpec.getSize(widthMeasureSpec);
|
||||
int mode = getViewMode(mViewWidth);
|
||||
if (mode != mMode) {
|
||||
// If the mode has changed, set the snippet line count to indicate layout required
|
||||
mMode = mode;
|
||||
mSnippetLineCount = NEEDS_LAYOUT;
|
||||
}
|
||||
mViewHeight = measureHeight(heightMeasureSpec, mMode);
|
||||
setMeasuredDimension(mViewWidth, mViewHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the height of this view
|
||||
*
|
||||
* @param measureSpec A measureSpec packed into an int
|
||||
* @param mode The current mode of this view
|
||||
* @return The height of the view, honoring constraints from measureSpec
|
||||
*/
|
||||
private int measureHeight(int measureSpec, int mode) {
|
||||
int result = 0;
|
||||
int specMode = MeasureSpec.getMode(measureSpec);
|
||||
int specSize = MeasureSpec.getSize(measureSpec);
|
||||
|
||||
if (specMode == MeasureSpec.EXACTLY) {
|
||||
// We were told how big to be
|
||||
result = specSize;
|
||||
} else {
|
||||
// Measure the text
|
||||
if (mMode == MODE_WIDE) {
|
||||
result = sItemHeightWide;
|
||||
} else {
|
||||
result = sItemHeightNarrow;
|
||||
}
|
||||
if (specMode == MeasureSpec.AT_MOST) {
|
||||
// Respect AT_MOST value if that was what is called for by
|
||||
// measureSpec
|
||||
result = Math.min(result, specSize);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (mSnippetLineCount == NEEDS_LAYOUT) {
|
||||
calculateDrawingData();
|
||||
}
|
||||
// Snippet starts at right of checkbox
|
||||
int snippetX = sCheckboxHitWidth;
|
||||
int snippetY;
|
||||
int lineHeight = (int)sDefaultPaint.getFontSpacing() + sPaddingVerySmall;
|
||||
FontMetricsInt fontMetrics = sDefaultPaint.getFontMetricsInt();
|
||||
int ascent = fontMetrics.ascent;
|
||||
int descent = fontMetrics.descent;
|
||||
int senderY;
|
||||
|
||||
if (mMode == MODE_WIDE) {
|
||||
// In wide mode, we'll use 1/4 for sender and 3/4 for snippet
|
||||
snippetX += mSenderSnippetWidth / 4;
|
||||
// And center the sender and snippet
|
||||
senderY = (mViewHeight - descent - ascent) / 2;
|
||||
snippetY = ((mViewHeight - (2 * lineHeight)) / 2) - ascent;
|
||||
} else {
|
||||
senderY = 20; // TODO Remove magic number
|
||||
snippetY = senderY + lineHeight + sPaddingVerySmall;
|
||||
}
|
||||
|
||||
// Draw the checkbox
|
||||
int checkboxLeft = (sCheckboxHitWidth - sSelectedIconOff.getWidth()) / 2;
|
||||
int checkboxTop = (mViewHeight - sSelectedIconOff.getHeight()) / 2;
|
||||
canvas.drawBitmap(mAdapter.isSelected(this) ? sSelectedIconOn : sSelectedIconOff,
|
||||
checkboxLeft, checkboxTop, sDefaultPaint);
|
||||
|
||||
// Draw the sender name
|
||||
canvas.drawText(mFormattedSender, 0, mFormattedSender.length(), sCheckboxHitWidth, senderY,
|
||||
mRead ? sDefaultPaint : sBoldPaint);
|
||||
|
||||
// Draw each of the snippet lines
|
||||
for (int i = 0; i < MAX_SUBJECT_SNIPPET_LINES; i++) {
|
||||
CharSequence line = mSnippetLines[i];
|
||||
if (line != null) {
|
||||
canvas.drawText(line, 0, line.length(), snippetX, snippetY, sDefaultPaint);
|
||||
snippetY += lineHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the attachment and invite icons, if necessary
|
||||
int left = mSenderSnippetWidth + sCheckboxHitWidth;
|
||||
if (mHasAttachment) {
|
||||
left -= sAttachmentIcon.getWidth() + sPaddingSmall;
|
||||
int iconTop = (mViewHeight - sAttachmentIcon.getHeight()) / 2;
|
||||
canvas.drawBitmap(sAttachmentIcon, left, iconTop, sDefaultPaint);
|
||||
}
|
||||
if (mHasInvite) {
|
||||
left -= sInviteIcon.getWidth() + sPaddingSmall;
|
||||
int iconTop = (mViewHeight - sInviteIcon.getHeight()) / 2;
|
||||
canvas.drawBitmap(sInviteIcon, left, iconTop, sDefaultPaint);
|
||||
}
|
||||
|
||||
// Draw the date
|
||||
int dateRight = mViewWidth - sPaddingMedium;
|
||||
if (mMode == MODE_WIDE) {
|
||||
dateRight -= sFavoriteHitWidth;
|
||||
}
|
||||
canvas.drawText(mFormattedDate, 0, mFormattedDate.length(), dateRight, senderY, sDatePaint);
|
||||
|
||||
// Draw the favorite icon
|
||||
int faveLeft = mViewWidth - sFavoriteIconLeft;
|
||||
int faveTop = (mViewHeight - sFavoriteIconOff.getHeight()) / 2;
|
||||
if (mMode == MODE_NARROW) {
|
||||
faveTop += sPaddingMedium;
|
||||
}
|
||||
canvas.drawBitmap(mIsFavorite ? sFavoriteIconOn : sFavoriteIconOff, faveLeft, faveTop,
|
||||
sDefaultPaint);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -69,7 +366,6 @@ public class MessageListItem extends RelativeLayout {
|
||||
*/
|
||||
public void bindViewInit(MessagesAdapter adapter) {
|
||||
mAdapter = adapter;
|
||||
mCachedViewPositions = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,21 +376,14 @@ public class MessageListItem extends RelativeLayout {
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
boolean handled = false;
|
||||
int touchX = (int) event.getX();
|
||||
|
||||
if (!mCachedViewPositions) {
|
||||
final float paddingScale = getContext().getResources().getDisplayMetrics().density;
|
||||
final int checkPadding = (int) ((CHECKMARK_PAD * paddingScale) + 0.5);
|
||||
final int starPadding = (int) ((STAR_PAD * paddingScale) + 0.5);
|
||||
mCheckRight = findViewById(R.id.selected).getRight() + checkPadding;
|
||||
mStarLeft = findViewById(R.id.favorite).getLeft() - starPadding;
|
||||
mCachedViewPositions = true;
|
||||
}
|
||||
int checkRight = sCheckboxHitWidth;
|
||||
int starLeft = mViewWidth - sFavoriteHitWidth;
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
if (touchX < mCheckRight) {
|
||||
if (touchX < checkRight || touchX > starLeft) {
|
||||
mDownEvent = true;
|
||||
if ((touchX < mCheckRight) || (touchX > mStarLeft)) {
|
||||
if ((touchX < checkRight) || (touchX > starLeft)) {
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
@ -106,12 +395,12 @@ public class MessageListItem extends RelativeLayout {
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (mDownEvent) {
|
||||
if (touchX < mCheckRight) {
|
||||
if (touchX < checkRight) {
|
||||
mAdapter.toggleSelected(this);
|
||||
handled = true;
|
||||
} else if (touchX > mStarLeft) {
|
||||
mFavorite = !mFavorite;
|
||||
mAdapter.updateFavorite(this, mFavorite);
|
||||
} else if (touchX > starLeft) {
|
||||
mIsFavorite = !mIsFavorite;
|
||||
mAdapter.updateFavorite(this, mIsFavorite);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
@ -119,7 +408,7 @@ public class MessageListItem extends RelativeLayout {
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
postInvalidate();
|
||||
invalidate();
|
||||
} else {
|
||||
handled = super.onTouchEvent(event);
|
||||
}
|
||||
|
@ -26,24 +26,14 @@ import com.android.email.provider.EmailContent.MessageColumns;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Loader;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.Resources.Theme;
|
||||
import android.content.res.TypedArray;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CursorAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@ -74,18 +64,6 @@ import java.util.Set;
|
||||
public static final int COLUMN_FLAGS = 9;
|
||||
public static final int COLUMN_SNIPPET = 10;
|
||||
|
||||
private final LayoutInflater mInflater;
|
||||
private final Drawable mFavoriteIconOn;
|
||||
private final Drawable mFavoriteIconOff;
|
||||
private final Drawable mSelectedIconOn;
|
||||
private final Drawable mSelectedIconOff;
|
||||
|
||||
private final ColorStateList mTextColorPrimary;
|
||||
private final ColorStateList mTextColorSecondary;
|
||||
|
||||
private final java.text.DateFormat mDateFormat;
|
||||
private final java.text.DateFormat mTimeFormat;
|
||||
|
||||
/**
|
||||
* Set of seleced message IDs.
|
||||
*/
|
||||
@ -107,23 +85,6 @@ import java.util.Set;
|
||||
public MessagesAdapter(Context context, Callback callback) {
|
||||
super(context.getApplicationContext(), null, 0 /* no auto requery */);
|
||||
mCallback = callback;
|
||||
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
Resources resources = context.getResources();
|
||||
mFavoriteIconOn = resources.getDrawable(R.drawable.btn_star_big_buttonless_dark_on);
|
||||
mFavoriteIconOff = resources.getDrawable(R.drawable.btn_star_big_buttonless_dark_off);
|
||||
mSelectedIconOn = resources.getDrawable(R.drawable.btn_check_buttonless_dark_on);
|
||||
mSelectedIconOff = resources.getDrawable(R.drawable.btn_check_buttonless_dark_off);
|
||||
|
||||
Theme theme = context.getTheme();
|
||||
TypedArray array;
|
||||
array = theme.obtainStyledAttributes(new int[] { android.R.attr.textColorPrimary });
|
||||
mTextColorPrimary = resources.getColorStateList(array.getResourceId(0, 0));
|
||||
array = theme.obtainStyledAttributes(new int[] { android.R.attr.textColorSecondary });
|
||||
mTextColorSecondary = resources.getColorStateList(array.getResourceId(0, 0));
|
||||
|
||||
mDateFormat = android.text.format.DateFormat.getDateFormat(context); // short date
|
||||
mTimeFormat = android.text.format.DateFormat.getTimeFormat(context); // 12/24 time
|
||||
}
|
||||
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
@ -163,23 +124,16 @@ import java.util.Set;
|
||||
itemView.mMailboxId = cursor.getLong(COLUMN_MAILBOX_KEY);
|
||||
itemView.mAccountId = cursor.getLong(COLUMN_ACCOUNT_KEY);
|
||||
itemView.mRead = cursor.getInt(COLUMN_READ) != 0;
|
||||
itemView.mFavorite = cursor.getInt(COLUMN_FAVORITE) != 0;
|
||||
itemView.mIsFavorite = cursor.getInt(COLUMN_FAVORITE) != 0;
|
||||
itemView.mHasInvite =
|
||||
(cursor.getInt(COLUMN_FLAGS) & Message.FLAG_INCOMING_MEETING_INVITE) != 0;
|
||||
itemView.mHasAttachment = cursor.getInt(COLUMN_ATTACHMENTS) != 0;
|
||||
itemView.mTimestamp = cursor.getLong(COLUMN_DATE);
|
||||
itemView.mSender = cursor.getString(COLUMN_DISPLAY_NAME);
|
||||
itemView.mSnippet = cursor.getString(COLUMN_SNIPPET);
|
||||
itemView.mSnippetLineCount = MessageListItem.NEEDS_LAYOUT;
|
||||
|
||||
// Load the UI
|
||||
View chipView = view.findViewById(R.id.chip);
|
||||
chipView.setBackgroundResource(Email.getAccountColorResourceId(itemView.mAccountId));
|
||||
|
||||
TextView fromView = (TextView) view.findViewById(R.id.from);
|
||||
String text = cursor.getString(COLUMN_DISPLAY_NAME);
|
||||
fromView.setText(text);
|
||||
|
||||
TextView subjectView = (TextView) view.findViewById(R.id.subject);
|
||||
text = cursor.getString(COLUMN_SUBJECT);
|
||||
// Add in the snippet if we have one
|
||||
// TODO Should this be spanned text?
|
||||
// The mocks show, for new messages, only the real subject in bold...
|
||||
// Would it be easier to simply use a 2nd TextView? This would also allow ellipsizing an
|
||||
// overly-long subject, to let the beautiful snippet shine through.
|
||||
String text = cursor.getString(COLUMN_SUBJECT);
|
||||
String snippet = cursor.getString(COLUMN_SNIPPET);
|
||||
if (!TextUtils.isEmpty(snippet)) {
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
@ -188,52 +142,15 @@ import java.util.Set;
|
||||
text = context.getString(R.string.message_list_snippet, text, snippet);
|
||||
}
|
||||
}
|
||||
subjectView.setText(text);
|
||||
|
||||
final boolean hasInvitation =
|
||||
(cursor.getInt(COLUMN_FLAGS) & Message.FLAG_INCOMING_MEETING_INVITE) != 0;
|
||||
makeVisible(view.findViewById(R.id.icon_invite), hasInvitation);
|
||||
final boolean hasAttachments = cursor.getInt(COLUMN_ATTACHMENTS) != 0;
|
||||
makeVisible(view.findViewById(R.id.icon_attachment), hasAttachments);
|
||||
|
||||
// TODO ui spec suggests "time", "day", "date" - implement "day"
|
||||
TextView dateView = (TextView) view.findViewById(R.id.date);
|
||||
long timestamp = cursor.getLong(COLUMN_DATE);
|
||||
Date date = new Date(timestamp);
|
||||
if (Utility.isDateToday(date)) {
|
||||
text = mTimeFormat.format(date);
|
||||
} else {
|
||||
text = mDateFormat.format(date);
|
||||
}
|
||||
dateView.setText(text);
|
||||
|
||||
if (itemView.mRead) {
|
||||
subjectView.setTypeface(Typeface.DEFAULT);
|
||||
fromView.setTypeface(Typeface.DEFAULT);
|
||||
fromView.setTextColor(mTextColorSecondary);
|
||||
} else {
|
||||
subjectView.setTypeface(Typeface.DEFAULT_BOLD);
|
||||
fromView.setTypeface(Typeface.DEFAULT_BOLD);
|
||||
fromView.setTextColor(mTextColorPrimary);
|
||||
}
|
||||
|
||||
updateCheckBox(itemView);
|
||||
changeFavoriteIcon(itemView, itemView.mFavorite);
|
||||
updateBackgroundColor(itemView);
|
||||
}
|
||||
|
||||
private static void makeVisible(View v, boolean visible) {
|
||||
v.setVisibility(visible ? View.VISIBLE : View.GONE);
|
||||
itemView.mSnippet = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
return mInflater.inflate(R.layout.message_list_item, parent, false);
|
||||
}
|
||||
|
||||
private void updateCheckBox(MessageListItem itemView) {
|
||||
ImageView selectedView = (ImageView) itemView.findViewById(R.id.selected);
|
||||
selectedView.setImageDrawable(isSelected(itemView) ? mSelectedIconOn : mSelectedIconOff);
|
||||
//return mInflater.inflate(R.layout.message_list_item, parent, false);
|
||||
MessageListItem item = new MessageListItem(context);
|
||||
item.setVisibility(View.VISIBLE);
|
||||
return item;
|
||||
}
|
||||
|
||||
public void toggleSelected(MessageListItem itemView) {
|
||||
@ -254,8 +171,6 @@ import java.util.Set;
|
||||
} else {
|
||||
mSelectedSet.remove(itemView.mMessageId);
|
||||
}
|
||||
updateCheckBox(itemView);
|
||||
updateBackgroundColor(itemView);
|
||||
if (mCallback != null) {
|
||||
mCallback.onAdapterSelectedChanged(itemView, newSelected, mSelectedSet.size());
|
||||
}
|
||||
@ -277,15 +192,7 @@ import java.util.Set;
|
||||
}
|
||||
|
||||
private void changeFavoriteIcon(MessageListItem view, boolean isFavorite) {
|
||||
((ImageView) view.findViewById(R.id.favorite)).setImageDrawable(
|
||||
isFavorite ? mFavoriteIconOn : mFavoriteIconOff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the background color according to the selection state.
|
||||
*/
|
||||
public void updateBackgroundColor(MessageListItem itemView) {
|
||||
// TODO Visual for selected items is not decided.
|
||||
view.invalidate();
|
||||
}
|
||||
|
||||
public static Loader<Cursor> createLoader(Context context, long mailboxId) {
|
||||
|
Loading…
Reference in New Issue
Block a user