Home | History | Annotate | Download | only in cardstream
      1 /*
      2 * Copyright 2013 The Android Open Source Project
      3 *
      4 * Licensed under the Apache License, Version 2.0 (the "License");
      5 * you may not use this file except in compliance with the License.
      6 * You may obtain a copy of the License at
      7 *
      8 *     http://www.apache.org/licenses/LICENSE-2.0
      9 *
     10 * Unless required by applicable law or agreed to in writing, software
     11 * distributed under the License is distributed on an "AS IS" BASIS,
     12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 * See the License for the specific language governing permissions and
     14 * limitations under the License.
     15 */
     16 
     17 
     18 package com.example.android.batchstepsensor.cardstream;
     19 
     20 import android.os.Bundle;
     21 import android.support.v4.app.Fragment;
     22 import android.view.LayoutInflater;
     23 import android.view.View;
     24 import android.view.ViewGroup;
     25 
     26 import java.util.Collection;
     27 import java.util.HashMap;
     28 import java.util.HashSet;
     29 import java.util.LinkedHashMap;
     30 
     31 import com.example.android.batchstepsensor.R;
     32 
     33 /**
     34  * A Fragment that handles a stream of cards.
     35  * Cards can be shown or hidden. When a card is shown it can also be marked as not-dismissible, see
     36  * {@link CardStreamLinearLayout#addCard(android.view.View, boolean)}.
     37  */
     38 public class CardStreamFragment extends Fragment {
     39 
     40     private static final int INITIAL_SIZE = 15;
     41     private CardStreamLinearLayout mLayout = null;
     42     private LinkedHashMap<String, Card> mVisibleCards = new LinkedHashMap<String, Card>(INITIAL_SIZE);
     43     private HashMap<String, Card> mHiddenCards = new HashMap<String, Card>(INITIAL_SIZE);
     44     private HashSet<String> mDismissibleCards = new HashSet<String>(INITIAL_SIZE);
     45 
     46     // Set the listener to handle dismissed cards by moving them to the hidden cards map.
     47     private CardStreamLinearLayout.OnDissmissListener mCardDismissListener =
     48             new CardStreamLinearLayout.OnDissmissListener() {
     49                 @Override
     50                 public void onDismiss(String tag) {
     51                     dismissCard(tag);
     52                 }
     53             };
     54 
     55 
     56     @Override
     57     public View onCreateView(LayoutInflater inflater, ViewGroup container,
     58                              Bundle savedInstanceState) {
     59 
     60         View view = inflater.inflate(R.layout.cardstream, container, false);
     61         mLayout = (CardStreamLinearLayout) view.findViewById(R.id.card_stream);
     62         mLayout.setOnDismissListener(mCardDismissListener);
     63 
     64         return view;
     65     }
     66 
     67     /**
     68      * Add a visible, dismissible card to the card stream.
     69      *
     70      * @param card
     71      */
     72     public void addCard(Card card) {
     73         final String tag = card.getTag();
     74 
     75         if (!mVisibleCards.containsKey(tag) && !mHiddenCards.containsKey(tag)) {
     76             final View view = card.getView();
     77             view.setTag(tag);
     78             mHiddenCards.put(tag, card);
     79         }
     80     }
     81 
     82     /**
     83      * Add and show a card.
     84      *
     85      * @param card
     86      * @param show
     87      */
     88     public void addCard(Card card, boolean show) {
     89         addCard(card);
     90         if (show) {
     91             showCard(card.getTag());
     92         }
     93     }
     94 
     95     /**
     96      * Remove a card and return true if it has been successfully removed.
     97      *
     98      * @param tag
     99      * @return
    100      */
    101     public boolean removeCard(String tag) {
    102         // Attempt to remove a visible card first
    103         Card card = mVisibleCards.get(tag);
    104         if (card != null) {
    105             // Card is visible, also remove from layout
    106             mVisibleCards.remove(tag);
    107             mLayout.removeView(card.getView());
    108             return true;
    109         } else {
    110             // Card is hidden, no need to remove from layout
    111             card = mHiddenCards.remove(tag);
    112             return card != null;
    113         }
    114     }
    115 
    116     /**
    117      * Show a dismissible card, returns false if the card could not be shown.
    118      *
    119      * @param tag
    120      * @return
    121      */
    122     public boolean showCard(String tag) {
    123         return showCard(tag, true);
    124     }
    125 
    126     /**
    127      * Show a card, returns false if the card could not be shown.
    128      *
    129      * @param tag
    130      * @param dismissible
    131      * @return
    132      */
    133     public boolean showCard(String tag, boolean dismissible) {
    134         final Card card = mHiddenCards.get(tag);
    135         // ensure the card is hidden and not already visible
    136         if (card != null && !mVisibleCards.containsValue(tag)) {
    137             mHiddenCards.remove(tag);
    138             mVisibleCards.put(tag, card);
    139             mLayout.addCard(card.getView(), dismissible);
    140             if (dismissible) {
    141                 mDismissibleCards.add(tag);
    142             }
    143             return true;
    144         }
    145         return false;
    146     }
    147 
    148     /**
    149      * Hides the card, returns false if the card could not be hidden.
    150      *
    151      * @param tag
    152      * @return
    153      */
    154     public boolean hideCard(String tag) {
    155         final Card card = mVisibleCards.get(tag);
    156         if (card != null) {
    157             mVisibleCards.remove(tag);
    158             mDismissibleCards.remove(tag);
    159             mHiddenCards.put(tag, card);
    160 
    161             mLayout.removeView(card.getView());
    162             return true;
    163         }
    164         return mHiddenCards.containsValue(tag);
    165     }
    166 
    167 
    168     private void dismissCard(String tag) {
    169         final Card card = mVisibleCards.get(tag);
    170         if (card != null) {
    171             mDismissibleCards.remove(tag);
    172             mVisibleCards.remove(tag);
    173             mHiddenCards.put(tag, card);
    174         }
    175     }
    176 
    177 
    178     public boolean isCardVisible(String tag) {
    179         return mVisibleCards.containsValue(tag);
    180     }
    181 
    182     /**
    183      * Returns true if the card is shown and is dismissible.
    184      *
    185      * @param tag
    186      * @return
    187      */
    188     public boolean isCardDismissible(String tag) {
    189         return mDismissibleCards.contains(tag);
    190     }
    191 
    192     /**
    193      * Returns the Card for this tag.
    194      *
    195      * @param tag
    196      * @return
    197      */
    198     public Card getCard(String tag) {
    199         final Card card = mVisibleCards.get(tag);
    200         if (card != null) {
    201             return card;
    202         } else {
    203             return mHiddenCards.get(tag);
    204         }
    205     }
    206 
    207     /**
    208      * Moves the view port to show the card with this tag.
    209      *
    210      * @param tag
    211      * @see CardStreamLinearLayout#setFirstVisibleCard(String)
    212      */
    213     public void setFirstVisibleCard(String tag) {
    214         final Card card = mVisibleCards.get(tag);
    215         if (card != null) {
    216             mLayout.setFirstVisibleCard(tag);
    217         }
    218     }
    219 
    220     public int getVisibleCardCount() {
    221         return mVisibleCards.size();
    222     }
    223 
    224     public Collection<Card> getVisibleCards() {
    225         return mVisibleCards.values();
    226     }
    227 
    228     public void restoreState(CardStreamState state, OnCardClickListener callback) {
    229         // restore hidden cards
    230         for (Card c : state.hiddenCards) {
    231             Card card = new Card.Builder(callback,c).build(getActivity());
    232             mHiddenCards.put(card.getTag(), card);
    233         }
    234 
    235         // temporarily set up list of dismissible
    236         final HashSet<String> dismissibleCards = state.dismissibleCards;
    237 
    238         //restore shown cards
    239         for (Card c : state.visibleCards) {
    240             Card card = new Card.Builder(callback,c).build(getActivity());
    241             addCard(card);
    242             final String tag = card.getTag();
    243             showCard(tag, dismissibleCards.contains(tag));
    244         }
    245 
    246         // move to first visible card
    247         final String firstShown = state.shownTag;
    248         if (firstShown != null) {
    249             mLayout.setFirstVisibleCard(firstShown);
    250         }
    251 
    252         mLayout.triggerShowInitialAnimation();
    253     }
    254 
    255     public CardStreamState dumpState() {
    256         final Card[] visible = cloneCards(mVisibleCards.values());
    257         final Card[] hidden = cloneCards(mHiddenCards.values());
    258         final HashSet<String> dismissible = new HashSet<String>(mDismissibleCards);
    259         final String firstVisible = mLayout.getFirstVisibleCardTag();
    260 
    261         return new CardStreamState(visible, hidden, dismissible, firstVisible);
    262     }
    263 
    264     private Card[] cloneCards(Collection<Card> cards) {
    265         Card[] cardArray = new Card[cards.size()];
    266         int i = 0;
    267         for (Card c : cards) {
    268             cardArray[i++] = c.createShallowClone();
    269         }
    270 
    271         return cardArray;
    272     }
    273 
    274 }
    275