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
}