blob: 5a4b66cb29b13561e756a350d7f0409bb461838f [file] [log] [blame]
/*
* 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);
}
}
}