Merge branch 'develop2' into imageGrid2
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / fragment / ExtendedListFragment.java
1 /* ownCloud Android client application
2 * Copyright (C) 2012 Bartek Przybylski
3 * Copyright (C) 2012-2013 ownCloud Inc.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2,
7 * as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19 package com.owncloud.android.ui.fragment;
20
21 import java.util.ArrayList;
22
23 import android.os.Bundle;
24 import android.support.v4.widget.SwipeRefreshLayout;
25 import android.view.LayoutInflater;
26 import android.view.View;
27 import android.view.ViewGroup;
28 import android.widget.AdapterView;
29 import android.widget.AdapterView.OnItemClickListener;
30 import android.widget.GridView;
31 import android.widget.ListAdapter;
32 import android.widget.ListView;
33 import android.widget.TextView;
34
35 import com.actionbarsherlock.app.SherlockFragment;
36 import com.owncloud.android.R;
37 import com.owncloud.android.lib.common.utils.Log_OC;
38 import com.owncloud.android.ui.ExtendedListView;
39 import com.owncloud.android.ui.activity.OnEnforceableRefreshListener;
40
41 /**
42 * TODO extending SherlockListFragment instead of SherlockFragment
43 */
44 public class ExtendedListFragment extends SherlockFragment
45 implements OnItemClickListener, OnEnforceableRefreshListener {
46
47 private static final String TAG = ExtendedListFragment.class.getSimpleName();
48
49 private static final String KEY_SAVED_LIST_POSITION = "SAVED_LIST_POSITION";
50 private static final String KEY_INDEXES = "INDEXES";
51 private static final String KEY_FIRST_POSITIONS= "FIRST_POSITIONS";
52 private static final String KEY_TOPS = "TOPS";
53 private static final String KEY_HEIGHT_CELL = "HEIGHT_CELL";
54 private static final String KEY_EMPTY_LIST_MESSAGE = "EMPTY_LIST_MESSAGE";
55
56 protected ExtendedListView mList;
57
58 private SwipeRefreshLayout mRefreshLayout;
59 private SwipeRefreshLayout mRefreshEmptyLayout;
60 private TextView mEmptyListMessage;
61
62 // Save the state of the scroll in browsing
63 private ArrayList<Integer> mIndexes;
64 private ArrayList<Integer> mFirstPositions;
65 private ArrayList<Integer> mTops;
66 private int mHeightCell = 0;
67
68 private OnEnforceableRefreshListener mOnRefreshListener = null;
69
70 protected GridView imageView;
71
72 public void setListAdapter(ListAdapter listAdapter) {
73 imageView.setAdapter(listAdapter);
74 imageView.invalidate();
75 }
76
77 public GridView getGridView() {
78 return imageView;
79 }
80 public void setFooterView(View footer) {
81 mList.addFooterView(footer, null, false);
82 mList.invalidate();
83 }
84
85
86
87 protected void switchImageView(){
88 imageView.setNumColumns(GridView.AUTO_FIT);
89 imageView.invalidate();
90 }
91
92 protected void switchFileView(){
93 imageView.setNumColumns(1);
94 imageView.invalidate();
95 }
96
97
98 @Override
99 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
100 Log_OC.e(TAG, "onCreateView");
101
102 View v = inflater.inflate(R.layout.list_fragment, null);
103
104 imageView = (ExtendedListView)(v.findViewById(R.id.list_root));
105 imageView.setOnItemClickListener(this);
106
107 if (savedInstanceState != null) {
108 int referencePosition = savedInstanceState.getInt(KEY_SAVED_LIST_POSITION);
109 setReferencePosition(referencePosition);
110 }
111
112 // Pull down refresh
113 mRefreshLayout = (SwipeRefreshLayout) v.findViewById(R.id.swipe_refresh_files);
114 mRefreshEmptyLayout = (SwipeRefreshLayout) v.findViewById(R.id.swipe_refresh_files_emptyView);
115
116 onCreateSwipeToRefresh(mRefreshLayout);
117 onCreateSwipeToRefresh(mRefreshEmptyLayout);
118
119 return v;
120 }
121
122 /**
123 * {@inheritDoc}
124 */
125 @Override
126 public void onActivityCreated(Bundle savedInstanceState) {
127 super.onActivityCreated(savedInstanceState);
128
129 if (savedInstanceState != null) {
130 mIndexes = savedInstanceState.getIntegerArrayList(KEY_INDEXES);
131 mFirstPositions = savedInstanceState.getIntegerArrayList(KEY_FIRST_POSITIONS);
132 mTops = savedInstanceState.getIntegerArrayList(KEY_TOPS);
133 mHeightCell = savedInstanceState.getInt(KEY_HEIGHT_CELL);
134 setMessageForEmptyList(savedInstanceState.getString(KEY_EMPTY_LIST_MESSAGE));
135
136 } else {
137 mIndexes = new ArrayList<Integer>();
138 mFirstPositions = new ArrayList<Integer>();
139 mTops = new ArrayList<Integer>();
140 mHeightCell = 0;
141 }
142 }
143
144
145 @Override
146 public void onSaveInstanceState(Bundle savedInstanceState) {
147 super.onSaveInstanceState(savedInstanceState);
148 Log_OC.e(TAG, "onSaveInstanceState()");
149 savedInstanceState.putInt(KEY_SAVED_LIST_POSITION, getReferencePosition());
150 savedInstanceState.putIntegerArrayList(KEY_INDEXES, mIndexes);
151 savedInstanceState.putIntegerArrayList(KEY_FIRST_POSITIONS, mFirstPositions);
152 savedInstanceState.putIntegerArrayList(KEY_TOPS, mTops);
153 savedInstanceState.putInt(KEY_HEIGHT_CELL, mHeightCell);
154 savedInstanceState.putString(KEY_EMPTY_LIST_MESSAGE, getEmptyViewText());
155 }
156
157 /**
158 * Calculates the position of the item that will be used as a reference to
159 * reposition the visible items in the list when the device is turned to
160 * other position.
161 *
162 * THe current policy is take as a reference the visible item in the center
163 * of the screen.
164 *
165 * @return The position in the list of the visible item in the center of the
166 * screen.
167 */
168 protected int getReferencePosition() {
169 if (imageView != null) {
170 return (imageView.getFirstVisiblePosition() + imageView.getLastVisiblePosition()) / 2;
171 } else {
172 return 0;
173 }
174 }
175
176 /**
177 * Sets the visible part of the list from the reference position.
178 *
179 * @param position Reference position previously returned by
180 * {@link LocalFileListFragment#getReferencePosition()}
181 */
182 protected void setReferencePosition(int position) {
183 if (imageView != null) {
184 imageView.setSelection(position);
185 }
186 }
187
188
189 /*
190 * Restore index and position
191 */
192 protected void restoreIndexAndTopPosition() {
193 if (mIndexes.size() > 0) {
194 // needs to be checked; not every browse-up had a browse-down before
195
196 int index = mIndexes.remove(mIndexes.size() - 1);
197
198 int firstPosition = mFirstPositions.remove(mFirstPositions.size() -1);
199
200 int top = mTops.remove(mTops.size() - 1);
201
202 imageView.smoothScrollToPosition(firstPosition);
203
204 // Move the scroll if the selection is not visible
205 int indexPosition = mHeightCell*index;
206 int height = imageView.getHeight();
207
208 if (indexPosition > height) {
209 imageView.smoothScrollToPosition(index);
210 }
211 }
212 }
213
214 /*
215 * Save index and top position
216 */
217 protected void saveIndexAndTopPosition(int index) {
218
219 mIndexes.add(index);
220
221 int firstPosition = imageView.getFirstVisiblePosition();
222 mFirstPositions.add(firstPosition);
223
224 View view = imageView.getChildAt(0);
225 int top = (view == null) ? 0 : view.getTop() ;
226
227 mTops.add(top);
228
229 // Save the height of a cell
230 mHeightCell = (view == null || mHeightCell != 0) ? mHeightCell : view.getHeight();
231 }
232
233
234 @Override
235 public void onItemClick (AdapterView<?> parent, View view, int position, long id) {
236 // to be @overriden
237 }
238
239 @Override
240 public void onRefresh() {
241 // to be @overriden
242 mRefreshLayout.setRefreshing(false);
243 mRefreshEmptyLayout.setRefreshing(false);
244
245 if (mOnRefreshListener != null) {
246 mOnRefreshListener.onRefresh();
247 }
248 }
249 public void setOnRefreshListener(OnEnforceableRefreshListener listener) {
250 mOnRefreshListener = listener;
251 }
252
253
254 /**
255 * Enables swipe gesture
256 */
257 public void enableSwipe() {
258 mRefreshLayout.setEnabled(true);
259 }
260
261 /**
262 * Disables swipe gesture. It prevents manual gestures but keeps the option you show
263 * refreshing programmatically.
264 */
265 public void disableSwipe() {
266 mRefreshLayout.setEnabled(false);
267 }
268
269 /**
270 * It shows the SwipeRefreshLayout progress
271 */
272 public void showSwipeProgress() {
273 mRefreshLayout.setRefreshing(true);
274 }
275
276 /**
277 * It shows the SwipeRefreshLayout progress
278 */
279 public void hideSwipeProgress() {
280 mRefreshLayout.setRefreshing(false);
281 }
282
283 /**
284 * Set message for empty list view
285 */
286 public void setMessageForEmptyList(String message) {
287 if (mEmptyListMessage != null) {
288 mEmptyListMessage.setText(message);
289 }
290 }
291
292 /**
293 * Get the text of EmptyListMessage TextView
294 *
295 * @return String
296 */
297 public String getEmptyViewText() {
298 return (mEmptyListMessage != null) ? mEmptyListMessage.getText().toString() : "";
299 }
300
301 private void onCreateSwipeToRefresh(SwipeRefreshLayout refreshLayout) {
302 // Colors in animations: background
303 refreshLayout.setColorScheme(R.color.background_color, R.color.background_color, R.color.background_color,
304 R.color.background_color);
305
306 refreshLayout.setOnRefreshListener(this);
307 }
308
309 @Override
310 public void onRefresh(boolean ignoreETag) {
311 mRefreshLayout.setRefreshing(false);
312 mRefreshEmptyLayout.setRefreshing(false);
313
314 if (mOnRefreshListener != null) {
315 mOnRefreshListener.onRefresh(ignoreETag);
316 }
317 }
318 }