ConversationViewHeader.java revision 57f82d24a7f7105800eff71083e41db5b27ba183
1/*
2 * Copyright (C) 2012 Google Inc.
3 * Licensed to The Android Open Source Project.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.mail.browse;
19
20import android.app.Activity;
21import android.app.AlertDialog;
22import android.app.Dialog;
23import android.app.DialogFragment;
24import android.content.ClipData;
25import android.content.ClipboardManager;
26import android.content.Context;
27import android.content.DialogInterface;
28import android.os.Bundle;
29import android.util.AttributeSet;
30import android.view.View;
31import android.view.View.OnClickListener;
32import android.view.ViewGroup;
33import android.widget.LinearLayout;
34
35import com.android.mail.R;
36import com.android.mail.browse.ConversationViewAdapter.ConversationHeaderItem;
37import com.android.mail.providers.Conversation;
38import com.android.mail.providers.UIProvider;
39import com.android.mail.ui.ConversationUpdater;
40import com.android.mail.utils.LogTag;
41import com.android.mail.utils.LogUtils;
42import com.android.mail.utils.Utils;
43
44/**
45 * A view for the subject and folders in the conversation view. This container
46 * makes an attempt to combine subject and folders on the same horizontal line if
47 * there is enough room to fit both without wrapping. If they overlap, it
48 * adjusts the layout to position the folders below the subject.
49 */
50public class ConversationViewHeader extends LinearLayout implements OnClickListener,
51        View.OnLongClickListener {
52
53    public interface ConversationViewHeaderCallbacks {
54        /**
55         * Called in response to a click on the folders region.
56         */
57        void onFoldersClicked();
58
59        /**
60         * Called when the height of the {@link ConversationViewHeader} changes.
61         *
62         * @param newHeight the new height in px
63         */
64        void onConversationViewHeaderHeightChange(int newHeight);
65
66        Activity getActivity();
67    }
68
69    private static final String LOG_TAG = LogTag.getLogTag();
70    private SubjectAndFolderView mSubjectAndFolderView;
71    private StarView mStarView;
72    private ConversationViewHeaderCallbacks mCallbacks;
73    private ConversationAccountController mAccountController;
74    private ConversationUpdater mConversationUpdater;
75    private ConversationHeaderItem mHeaderItem;
76    private Conversation mConversation;
77
78    /**
79     * Instantiated from this layout: conversation_view_header.xml
80     * @param context
81     */
82    public ConversationViewHeader(Context context) {
83        this(context, null);
84    }
85
86    public ConversationViewHeader(Context context, AttributeSet attrs) {
87        super(context, attrs);
88    }
89
90    @Override
91    protected void onFinishInflate() {
92        super.onFinishInflate();
93
94        mSubjectAndFolderView =
95                (SubjectAndFolderView) findViewById(R.id.subject_and_folder_view);
96        mSubjectAndFolderView.setOnLongClickListener(this);
97        mStarView = (StarView) findViewById(R.id.conversation_header_star);
98        mStarView.setOnClickListener(this);
99    }
100
101    public void setCallbacks(ConversationViewHeaderCallbacks callbacks,
102            ConversationAccountController accountController,
103            ConversationUpdater conversationUpdater) {
104        mCallbacks = callbacks;
105        mAccountController = accountController;
106        mConversationUpdater = conversationUpdater;
107    }
108
109    public void setSubject(final String subject) {
110        mSubjectAndFolderView.setSubject(subject);
111    }
112
113    public void setFolders(Conversation conv) {
114        mSubjectAndFolderView.setFolders(mCallbacks, mAccountController.getAccount(), conv);
115    }
116
117    public void setStarred(boolean isStarred) {
118        mStarView.setStarred(isStarred);
119        boolean showStar = mConversation != null && !mConversation.isInTrash();
120        mStarView.setStarred(isStarred);
121        mStarView.setVisibility(showStar ? View.VISIBLE : View.INVISIBLE);
122    }
123
124    public void bind(ConversationHeaderItem headerItem) {
125        mHeaderItem = headerItem;
126        mConversation = mHeaderItem.mConversation;
127        if (mSubjectAndFolderView != null) {
128            mSubjectAndFolderView.bind(headerItem);
129        }
130        setStarred(mConversation.starred);
131    }
132
133    private int measureHeight() {
134        ViewGroup parent = (ViewGroup) getParent();
135        if (parent == null) {
136            LogUtils.e(LOG_TAG, "Unable to measure height of conversation header");
137            return getHeight();
138        }
139        final int h = Utils.measureViewHeight(this, parent);
140        return h;
141    }
142
143    /**
144     * Update the conversation view header to reflect the updated conversation.
145     */
146    public void onConversationUpdated(Conversation conv) {
147        // The only things we have to worry about when the conversation changes
148        // in the conversation header are the folders, priority indicators, and starred state.
149        // Updating these will resize the space for the header.
150        mConversation = conv;
151        setSubject(conv.subject);
152        setFolders(conv);
153        setStarred(conv.starred);
154        if (mHeaderItem != null) {
155            final int h = measureHeight();
156            if (mHeaderItem.setHeight(h)) {
157                mCallbacks.onConversationViewHeaderHeightChange(h);
158            }
159        }
160    }
161
162    @Override
163    public void onClick(View v) {
164        final int id = v.getId();
165        if (mConversation != null && id == R.id.conversation_header_star) {
166            mConversation.starred = !mConversation.starred;
167            setStarred(mConversation.starred);
168            mConversationUpdater.updateConversation(Conversation.listOf(mConversation),
169                    UIProvider.ConversationColumns.STARRED, mConversation.starred);
170        }
171    }
172
173    @Override
174    public boolean onLongClick(View v) {
175        final DialogFragment frag =
176                CopySubjectDialog.newInstance(mSubjectAndFolderView.getSubject());
177        frag.show(mCallbacks.getActivity().getFragmentManager(), CopySubjectDialog.TAG);
178        return true;
179    }
180
181    public static class CopySubjectDialog extends DialogFragment
182            implements DialogInterface.OnClickListener {
183
184        public static final String TAG = "copy-subject-dialog";
185
186        private static final String ARG_SUBJECT = "subject";
187
188        private String mSubject;
189
190        public static CopySubjectDialog newInstance(String subject) {
191            final CopySubjectDialog frag = new CopySubjectDialog();
192            final Bundle args = new Bundle(1);
193            args.putString(ARG_SUBJECT, subject);
194            frag.setArguments(args);
195            return frag;
196        }
197
198        public CopySubjectDialog() {}
199
200        @Override
201        public Dialog onCreateDialog(Bundle savedInstanceState) {
202            mSubject = getArguments().getString(ARG_SUBJECT);
203            return new AlertDialog.Builder(getActivity())
204                    .setMessage(mSubject)
205                    .setPositiveButton(R.string.contextmenu_copy, this)
206                    .setNegativeButton(R.string.cancel, this)
207                    .create();
208        }
209
210        @Override
211        public void onClick(DialogInterface dialog, int which) {
212            if (which == DialogInterface.BUTTON_POSITIVE) {
213                final ClipboardManager clipboard = (ClipboardManager)
214                        getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
215                clipboard.setPrimaryClip(ClipData.newPlainText(null, mSubject));
216            }
217        }
218    }
219}
220