Home | History | Annotate | Download | only in browse
      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 
     18 package com.android.mail.browse;
     19 
     20 import android.app.Activity;
     21 import android.app.AlertDialog;
     22 import android.app.Dialog;
     23 import android.app.DialogFragment;
     24 import android.content.ClipData;
     25 import android.content.ClipboardManager;
     26 import android.content.Context;
     27 import android.content.DialogInterface;
     28 import android.os.Bundle;
     29 import android.util.AttributeSet;
     30 import android.view.View;
     31 import android.view.View.OnClickListener;
     32 import android.view.ViewGroup;
     33 import android.widget.LinearLayout;
     34 
     35 import com.android.mail.R;
     36 import com.android.mail.browse.ConversationViewAdapter.ConversationHeaderItem;
     37 import com.android.mail.providers.Conversation;
     38 import com.android.mail.providers.UIProvider;
     39 import com.android.mail.ui.ConversationUpdater;
     40 import com.android.mail.utils.LogTag;
     41 import com.android.mail.utils.LogUtils;
     42 import 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  */
     50 public 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