/* * Copyright 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.batchstepsensor.cardstream; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import com.example.android.batchstepsensor.R; /** * A Fragment that handles a stream of cards. * Cards can be shown or hidden. When a card is shown it can also be marked as not-dismissible, see * {@link CardStreamLinearLayout#addCard(android.view.View, boolean)}. */ public class CardStreamFragment extends Fragment { private static final int INITIAL_SIZE = 15; private CardStreamLinearLayout mLayout = null; private LinkedHashMap<String, Card> mVisibleCards = new LinkedHashMap<String, Card>(INITIAL_SIZE); private HashMap<String, Card> mHiddenCards = new HashMap<String, Card>(INITIAL_SIZE); private HashSet<String> mDismissibleCards = new HashSet<String>(INITIAL_SIZE); // Set the listener to handle dismissed cards by moving them to the hidden cards map. private CardStreamLinearLayout.OnDissmissListener mCardDismissListener = new CardStreamLinearLayout.OnDissmissListener() { @Override public void onDismiss(String tag) { dismissCard(tag); } }; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.cardstream, container, false); mLayout = (CardStreamLinearLayout) view.findViewById(R.id.card_stream); mLayout.setOnDismissListener(mCardDismissListener); return view; } /** * Add a visible, dismissible card to the card stream. * * @param card */ public void addCard(Card card) { final String tag = card.getTag(); if (!mVisibleCards.containsKey(tag) && !mHiddenCards.containsKey(tag)) { final View view = card.getView(); view.setTag(tag); mHiddenCards.put(tag, card); } } /** * Add and show a card. * * @param card * @param show */ public void addCard(Card card, boolean show) { addCard(card); if (show) { showCard(card.getTag()); } } /** * Remove a card and return true if it has been successfully removed. * * @param tag * @return */ public boolean removeCard(String tag) { // Attempt to remove a visible card first Card card = mVisibleCards.get(tag); if (card != null) { // Card is visible, also remove from layout mVisibleCards.remove(tag); mLayout.removeView(card.getView()); return true; } else { // Card is hidden, no need to remove from layout card = mHiddenCards.remove(tag); return card != null; } } /** * Show a dismissible card, returns false if the card could not be shown. * * @param tag * @return */ public boolean showCard(String tag) { return showCard(tag, true); } /** * Show a card, returns false if the card could not be shown. * * @param tag * @param dismissible * @return */ public boolean showCard(String tag, boolean dismissible) { final Card card = mHiddenCards.get(tag); // ensure the card is hidden and not already visible if (card != null && !mVisibleCards.containsValue(tag)) { mHiddenCards.remove(tag); mVisibleCards.put(tag, card); mLayout.addCard(card.getView(), dismissible); if (dismissible) { mDismissibleCards.add(tag); } return true; } return false; } /** * Hides the card, returns false if the card could not be hidden. * * @param tag * @return */ public boolean hideCard(String tag) { final Card card = mVisibleCards.get(tag); if (card != null) { mVisibleCards.remove(tag); mDismissibleCards.remove(tag); mHiddenCards.put(tag, card); mLayout.removeView(card.getView()); return true; } return mHiddenCards.containsValue(tag); } private void dismissCard(String tag) { final Card card = mVisibleCards.get(tag); if (card != null) { mDismissibleCards.remove(tag); mVisibleCards.remove(tag); mHiddenCards.put(tag, card); } } public boolean isCardVisible(String tag) { return mVisibleCards.containsValue(tag); } /** * Returns true if the card is shown and is dismissible. * * @param tag * @return */ public boolean isCardDismissible(String tag) { return mDismissibleCards.contains(tag); } /** * Returns the Card for this tag. * * @param tag * @return */ public Card getCard(String tag) { final Card card = mVisibleCards.get(tag); if (card != null) { return card; } else { return mHiddenCards.get(tag); } } /** * Moves the view port to show the card with this tag. * * @param tag * @see CardStreamLinearLayout#setFirstVisibleCard(String) */ public void setFirstVisibleCard(String tag) { final Card card = mVisibleCards.get(tag); if (card != null) { mLayout.setFirstVisibleCard(tag); } } public int getVisibleCardCount() { return mVisibleCards.size(); } public Collection<Card> getVisibleCards() { return mVisibleCards.values(); } public void restoreState(CardStreamState state, OnCardClickListener callback) { // restore hidden cards for (Card c : state.hiddenCards) { Card card = new Card.Builder(callback,c).build(getActivity()); mHiddenCards.put(card.getTag(), card); } // temporarily set up list of dismissible final HashSet<String> dismissibleCards = state.dismissibleCards; //restore shown cards for (Card c : state.visibleCards) { Card card = new Card.Builder(callback,c).build(getActivity()); addCard(card); final String tag = card.getTag(); showCard(tag, dismissibleCards.contains(tag)); } // move to first visible card final String firstShown = state.shownTag; if (firstShown != null) { mLayout.setFirstVisibleCard(firstShown); } mLayout.triggerShowInitialAnimation(); } public CardStreamState dumpState() { final Card[] visible = cloneCards(mVisibleCards.values()); final Card[] hidden = cloneCards(mHiddenCards.values()); final HashSet<String> dismissible = new HashSet<String>(mDismissibleCards); final String firstVisible = mLayout.getFirstVisibleCardTag(); return new CardStreamState(visible, hidden, dismissible, firstVisible); } private Card[] cloneCards(Collection<Card> cards) { Card[] cardArray = new Card[cards.size()]; int i = 0; for (Card c : cards) { cardArray[i++] = c.createShallowClone(); } return cardArray; } }