| /* |
| * Copyright (C) 2012 Google Inc. |
| * Licensed to 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. |
| */ |
| |
| package com.android.mail.browse; |
| |
| import android.content.Context; |
| import android.content.res.Resources; |
| import android.os.Build; |
| import android.text.Spannable; |
| import android.text.SpannableStringBuilder; |
| import android.text.TextUtils; |
| import android.text.style.BackgroundColorSpan; |
| import android.text.style.ForegroundColorSpan; |
| import android.util.AttributeSet; |
| import android.util.TypedValue; |
| import android.view.View; |
| import android.view.View.OnClickListener; |
| import android.view.ViewGroup; |
| import android.widget.LinearLayout; |
| import android.widget.TextView; |
| |
| import com.android.mail.R; |
| import com.android.mail.browse.ConversationViewAdapter.ConversationHeaderItem; |
| import com.android.mail.browse.FolderSpan.FolderSpanDimensions; |
| import com.android.mail.providers.Conversation; |
| import com.android.mail.providers.Folder; |
| import com.android.mail.providers.Settings; |
| import com.android.mail.ui.FolderDisplayer; |
| import com.android.mail.utils.LogTag; |
| import com.android.mail.utils.LogUtils; |
| import com.android.mail.utils.Utils; |
| |
| /** |
| * A view for the subject and folders in the conversation view. This container |
| * makes an attempt to combine subject and folders on the same horizontal line if |
| * there is enough room to fit both without wrapping. If they overlap, it |
| * adjusts the layout to position the folders below the subject. |
| */ |
| public class ConversationViewHeader extends LinearLayout implements OnClickListener { |
| |
| public interface ConversationViewHeaderCallbacks { |
| /** |
| * Called in response to a click on the folders region. |
| */ |
| void onFoldersClicked(); |
| |
| /** |
| * Called when the height of the {@link ConversationViewHeader} changes. |
| * |
| * @param newHeight the new height in px |
| */ |
| void onConversationViewHeaderHeightChange(int newHeight); |
| } |
| |
| private static final String LOG_TAG = LogTag.getLogTag(); |
| private TextView mSubjectView; |
| private FolderSpanTextView mFoldersView; |
| private ConversationViewHeaderCallbacks mCallbacks; |
| private ConversationAccountController mAccountController; |
| private ConversationFolderDisplayer mFolderDisplayer; |
| private ConversationHeaderItem mHeaderItem; |
| |
| private boolean mLargeText; |
| private final float mCondensedTextSize; |
| private final int mCondensedTopPadding; |
| |
| /** |
| * Instantiated from this layout: conversation_view_header.xml |
| * @param context |
| */ |
| public ConversationViewHeader(Context context) { |
| this(context, null); |
| } |
| |
| public ConversationViewHeader(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| mLargeText = true; |
| final Resources resources = getResources(); |
| mCondensedTextSize = |
| resources.getDimensionPixelSize(R.dimen.conversation_header_font_size_condensed); |
| mCondensedTopPadding = resources.getDimensionPixelSize( |
| R.dimen.conversation_header_vertical_padding_condensed); |
| } |
| |
| @Override |
| protected void onFinishInflate() { |
| super.onFinishInflate(); |
| |
| mSubjectView = (TextView) findViewById(R.id.subject); |
| mFoldersView = (FolderSpanTextView) findViewById(R.id.folders); |
| |
| mFoldersView.setOnClickListener(this); |
| mFolderDisplayer = new ConversationFolderDisplayer(getContext(), mFoldersView); |
| } |
| |
| @Override |
| protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
| super.onMeasure(widthMeasureSpec, heightMeasureSpec); |
| |
| // If we currently have large text and we have greater than 2 lines, |
| // switch to smaller text size with smaller top padding and re-measure |
| if (mLargeText && mSubjectView.getLineCount() > 2) { |
| mSubjectView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mCondensedTextSize); |
| |
| if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { |
| // start, top, end, bottom |
| mSubjectView.setPaddingRelative(mSubjectView.getPaddingStart(), |
| mCondensedTopPadding, mSubjectView.getPaddingEnd(), |
| mSubjectView.getPaddingBottom()); |
| } else { |
| mSubjectView.setPadding(mSubjectView.getPaddingLeft(), |
| mCondensedTopPadding, mSubjectView.getPaddingRight(), |
| mSubjectView.getPaddingBottom()); |
| } |
| |
| super.onMeasure(widthMeasureSpec, heightMeasureSpec); |
| } |
| } |
| |
| public void setCallbacks(ConversationViewHeaderCallbacks callbacks, |
| ConversationAccountController accountController) { |
| mCallbacks = callbacks; |
| mAccountController = accountController; |
| } |
| |
| public void setSubject(final String subject) { |
| mSubjectView.setText(subject); |
| if (TextUtils.isEmpty(subject)) { |
| mSubjectView.setVisibility(GONE); |
| } |
| } |
| |
| public void setFoldersVisible(boolean show) { |
| mFoldersView.setVisibility(show ? View.VISIBLE : View.GONE); |
| } |
| |
| public void setFolders(Conversation conv) { |
| setFoldersVisible(true); |
| SpannableStringBuilder sb = new SpannableStringBuilder(); |
| final Settings settings = mAccountController.getAccount().settings; |
| if (settings.priorityArrowsEnabled && conv.isImportant()) { |
| sb.append('.'); |
| sb.setSpan(new PriorityIndicatorSpan(getContext(), |
| R.drawable.ic_email_caret_none_important_unread, mFoldersView.getPadding(), 0, |
| mFoldersView.getPaddingAbove()), |
| 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); |
| } |
| |
| mFolderDisplayer.loadConversationFolders(conv, null /* ignoreFolder */, |
| -1 /* ignoreFolderType */); |
| mFolderDisplayer.appendFolderSpans(sb); |
| |
| mFoldersView.setText(sb); |
| } |
| |
| public void bind(ConversationHeaderItem headerItem) { |
| mHeaderItem = headerItem; |
| } |
| |
| private int measureHeight() { |
| ViewGroup parent = (ViewGroup) getParent(); |
| if (parent == null) { |
| LogUtils.e(LOG_TAG, "Unable to measure height of conversation header"); |
| return getHeight(); |
| } |
| final int h = Utils.measureViewHeight(this, parent); |
| return h; |
| } |
| |
| /** |
| * Update the conversation view header to reflect the updated conversation. |
| */ |
| public void onConversationUpdated(Conversation conv) { |
| // The only things we have to worry about when the conversation changes |
| // in the conversation header are the folders and priority indicators. |
| // Updating these will resize the space for the header. |
| setFolders(conv); |
| if (mHeaderItem != null) { |
| final int h = measureHeight(); |
| if (mHeaderItem.setHeight(h)) { |
| mCallbacks.onConversationViewHeaderHeightChange(h); |
| } |
| } |
| } |
| |
| @Override |
| public void onClick(View v) { |
| if (R.id.folders == v.getId()) { |
| if (mCallbacks != null) { |
| mCallbacks.onFoldersClicked(); |
| } |
| } |
| } |
| |
| private static class ConversationFolderDisplayer extends FolderDisplayer { |
| |
| private FolderSpanDimensions mDims; |
| |
| public ConversationFolderDisplayer(Context context, FolderSpanDimensions dims) { |
| super(context); |
| mDims = dims; |
| } |
| |
| public void appendFolderSpans(SpannableStringBuilder sb) { |
| for (final Folder f : mFoldersSortedSet) { |
| final int bgColor = f.getBackgroundColor(mDefaultBgColor); |
| final int fgColor = f.getForegroundColor(mDefaultFgColor); |
| addSpan(sb, f.name, bgColor, fgColor); |
| } |
| |
| if (mFoldersSortedSet.isEmpty()) { |
| final Resources r = mContext.getResources(); |
| final String name = r.getString(R.string.add_label); |
| final int bgColor = r.getColor(R.color.conv_header_add_label_background); |
| final int fgColor = r.getColor(R.color.conv_header_add_label_text); |
| addSpan(sb, name, bgColor, fgColor); |
| } |
| } |
| |
| private void addSpan(SpannableStringBuilder sb, String name, int bgColor, |
| int fgColor) { |
| final int start = sb.length(); |
| sb.append(name); |
| final int end = sb.length(); |
| |
| sb.setSpan(new BackgroundColorSpan(bgColor), start, end, |
| Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| sb.setSpan(new ForegroundColorSpan(fgColor), start, end, |
| Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| sb.setSpan(new FolderSpan(sb, mDims), start, end, |
| Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| } |
| |
| } |
| } |