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