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