Merge branch 'text_file_preview_pr_707_with_develop' of github.com:owncloud/android...
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / preview / PreviewImagePagerAdapter.java
1 /**
2 * ownCloud Android client application
3 *
4 * @author David A. Velasco
5 * Copyright (C) 2015 ownCloud Inc.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2,
9 * as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20 package com.owncloud.android.ui.preview;
21
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.Iterator;
25 import java.util.Map;
26 import java.util.Set;
27 import java.util.Vector;
28
29 import android.accounts.Account;
30 import android.support.v4.app.Fragment;
31 import android.support.v4.app.FragmentManager;
32 import android.support.v4.app.FragmentStatePagerAdapter;
33 import android.view.ViewGroup;
34
35 import com.owncloud.android.datamodel.FileDataStorageManager;
36 import com.owncloud.android.datamodel.OCFile;
37 import com.owncloud.android.ui.fragment.FileFragment;
38 import com.owncloud.android.utils.FileStorageUtils;
39
40 /**
41 * Adapter class that provides Fragment instances
42 */
43 //public class PreviewImagePagerAdapter extends PagerAdapter {
44 public class PreviewImagePagerAdapter extends FragmentStatePagerAdapter {
45
46 private Vector<OCFile> mImageFiles;
47 private Account mAccount;
48 private Set<Object> mObsoleteFragments;
49 private Set<Integer> mObsoletePositions;
50 private Set<Integer> mDownloadErrors;
51 private FileDataStorageManager mStorageManager;
52
53 private Map<Integer, FileFragment> mCachedFragments;
54
55 /**
56 * Constructor.
57 *
58 * @param fragmentManager {@link FragmentManager} instance that will handle
59 * the {@link Fragment}s provided by the adapter.
60 * @param parentFolder Folder where images will be searched for.
61 * @param storageManager Bridge to database.
62 */
63 public PreviewImagePagerAdapter(FragmentManager fragmentManager, OCFile parentFolder,
64 Account account, FileDataStorageManager storageManager /*,
65 boolean onlyOnDevice*/) {
66 super(fragmentManager);
67
68 if (fragmentManager == null) {
69 throw new IllegalArgumentException("NULL FragmentManager instance");
70 }
71 if (parentFolder == null) {
72 throw new IllegalArgumentException("NULL parent folder");
73 }
74 if (storageManager == null) {
75 throw new IllegalArgumentException("NULL storage manager");
76 }
77
78 mAccount = account;
79 mStorageManager = storageManager;
80 // TODO Enable when "On Device" is recovered ?
81 mImageFiles = mStorageManager.getFolderImages(parentFolder/*, false*/);
82
83 mImageFiles = FileStorageUtils.sortFolder(mImageFiles);
84
85 mObsoleteFragments = new HashSet<Object>();
86 mObsoletePositions = new HashSet<Integer>();
87 mDownloadErrors = new HashSet<Integer>();
88 //mFragmentManager = fragmentManager;
89 mCachedFragments = new HashMap<Integer, FileFragment>();
90 }
91
92 /**
93 * Returns the image files handled by the adapter.
94 *
95 * @return A vector with the image files handled by the adapter.
96 */
97 protected OCFile getFileAt(int position) {
98 return mImageFiles.get(position);
99 }
100
101
102 public Fragment getItem(int i) {
103 OCFile file = mImageFiles.get(i);
104 Fragment fragment = null;
105 if (file.isDown()) {
106 fragment = PreviewImageFragment.newInstance(file,
107 mObsoletePositions.contains(Integer.valueOf(i)));
108
109 } else if (mDownloadErrors.contains(Integer.valueOf(i))) {
110 fragment = FileDownloadFragment.newInstance(file, mAccount, true);
111 ((FileDownloadFragment)fragment).setError(true);
112 mDownloadErrors.remove(Integer.valueOf(i));
113
114 } else {
115 fragment = FileDownloadFragment.newInstance(
116 file, mAccount, mObsoletePositions.contains(Integer.valueOf(i))
117 );
118 }
119 mObsoletePositions.remove(Integer.valueOf(i));
120 return fragment;
121 }
122
123 public int getFilePosition(OCFile file) {
124 return mImageFiles.indexOf(file);
125 }
126
127 @Override
128 public int getCount() {
129 return mImageFiles.size();
130 }
131
132 @Override
133 public CharSequence getPageTitle(int position) {
134 return mImageFiles.get(position).getFileName();
135 }
136
137
138 public void updateFile(int position, OCFile file) {
139 FileFragment fragmentToUpdate = mCachedFragments.get(Integer.valueOf(position));
140 if (fragmentToUpdate != null) {
141 mObsoleteFragments.add(fragmentToUpdate);
142 }
143 mObsoletePositions.add(Integer.valueOf(position));
144 mImageFiles.set(position, file);
145 }
146
147
148 public void updateWithDownloadError(int position) {
149 FileFragment fragmentToUpdate = mCachedFragments.get(Integer.valueOf(position));
150 if (fragmentToUpdate != null) {
151 mObsoleteFragments.add(fragmentToUpdate);
152 }
153 mDownloadErrors.add(Integer.valueOf(position));
154 }
155
156 public void clearErrorAt(int position) {
157 FileFragment fragmentToUpdate = mCachedFragments.get(Integer.valueOf(position));
158 if (fragmentToUpdate != null) {
159 mObsoleteFragments.add(fragmentToUpdate);
160 }
161 mDownloadErrors.remove(Integer.valueOf(position));
162 }
163
164
165 @Override
166 public int getItemPosition(Object object) {
167 if (mObsoleteFragments.contains(object)) {
168 mObsoleteFragments.remove(object);
169 return POSITION_NONE;
170 }
171 return super.getItemPosition(object);
172 }
173
174
175 @Override
176 public Object instantiateItem(ViewGroup container, int position) {
177 Object fragment = super.instantiateItem(container, position);
178 mCachedFragments.put(Integer.valueOf(position), (FileFragment)fragment);
179 return fragment;
180 }
181
182 @Override
183 public void destroyItem(ViewGroup container, int position, Object object) {
184 mCachedFragments.remove(Integer.valueOf(position));
185 super.destroyItem(container, position, object);
186 }
187
188
189 public boolean pendingErrorAt(int position) {
190 return mDownloadErrors.contains(Integer.valueOf(position));
191 }
192
193 /**
194 * Reset the image zoom to default value for each CachedFragments
195 */
196 public void resetZoom() {
197 Iterator<FileFragment> entries = mCachedFragments.values().iterator();
198 while (entries.hasNext()) {
199 FileFragment fileFragment = (FileFragment) entries.next();
200 if (fileFragment instanceof PreviewImageFragment) {
201 ((PreviewImageFragment) fileFragment).getImageView().resetZoom();
202 }
203 }
204 }
205
206 /* -*
207 * Called when a change in the shown pages is going to start being made.
208 *
209 * @param container The containing View which is displaying this adapter's page views.
210 *- /
211 @Override
212 public void startUpdate(ViewGroup container) {
213 Log_OC.e(TAG, "** startUpdate");
214 }
215
216 @Override
217 public Object instantiateItem(ViewGroup container, int position) {
218 Log_OC.e(TAG, "** instantiateItem " + position);
219
220 if (mFragments.size() > position) {
221 Fragment fragment = mFragments.get(position);
222 if (fragment != null) {
223 Log_OC.e(TAG, "** \t returning cached item");
224 return fragment;
225 }
226 }
227
228 if (mCurTransaction == null) {
229 mCurTransaction = mFragmentManager.beginTransaction();
230 }
231
232 Fragment fragment = getItem(position);
233 if (mSavedState.size() > position) {
234 Fragment.SavedState savedState = mSavedState.get(position);
235 if (savedState != null) {
236 // TODO WATCH OUT:
237 // * The Fragment must currently be attached to the FragmentManager.
238 // * A new Fragment created using this saved state must be the same class type as the Fragment it was created from.
239 // * The saved state can not contain dependencies on other fragments -- that is it can't use putFragment(Bundle, String, Fragment)
240 // to store a fragment reference
241 fragment.setInitialSavedState(savedState);
242 }
243 }
244 while (mFragments.size() <= position) {
245 mFragments.add(null);
246 }
247 fragment.setMenuVisibility(false);
248 mFragments.set(position, fragment);
249 //Log_OC.e(TAG, "** \t adding fragment at position " + position + ", containerId " + container.getId());
250 mCurTransaction.add(container.getId(), fragment);
251
252 return fragment;
253 }
254
255 @Override
256 public void destroyItem(ViewGroup container, int position, Object object) {
257 Log_OC.e(TAG, "** destroyItem " + position);
258 Fragment fragment = (Fragment)object;
259
260 if (mCurTransaction == null) {
261 mCurTransaction = mFragmentManager.beginTransaction();
262 }
263 Log_OC.e(TAG, "** \t removing fragment at position " + position);
264 while (mSavedState.size() <= position) {
265 mSavedState.add(null);
266 }
267 mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment));
268 mFragments.set(position, null);
269
270 mCurTransaction.remove(fragment);
271 }
272
273 @Override
274 public void setPrimaryItem(ViewGroup container, int position, Object object) {
275 Fragment fragment = (Fragment)object;
276 if (fragment != mCurrentPrimaryItem) {
277 if (mCurrentPrimaryItem != null) {
278 mCurrentPrimaryItem.setMenuVisibility(false);
279 }
280 if (fragment != null) {
281 fragment.setMenuVisibility(true);
282 }
283 mCurrentPrimaryItem = fragment;
284 }
285 }
286
287 @Override
288 public void finishUpdate(ViewGroup container) {
289 Log_OC.e(TAG, "** finishUpdate (start)");
290 if (mCurTransaction != null) {
291 mCurTransaction.commitAllowingStateLoss();
292 mCurTransaction = null;
293 mFragmentManager.executePendingTransactions();
294 }
295 Log_OC.e(TAG, "** finishUpdate (end)");
296 }
297
298 @Override
299 public boolean isViewFromObject(View view, Object object) {
300 return ((Fragment)object).getView() == view;
301 }
302
303 @Override
304 public Parcelable saveState() {
305 Bundle state = null;
306 if (mSavedState.size() > 0) {
307 state = new Bundle();
308 Fragment.SavedState[] savedStates = new Fragment.SavedState[mSavedState.size()];
309 mSavedState.toArray(savedStates);
310 state.putParcelableArray("states", savedStates);
311 }
312 for (int i=0; i<mFragments.size(); i++) {
313 Fragment fragment = mFragments.get(i);
314 if (fragment != null) {
315 if (state == null) {
316 state = new Bundle();
317 }
318 String key = "f" + i;
319 mFragmentManager.putFragment(state, key, fragment);
320 }
321 }
322 return state;
323 }
324
325 @Override
326 public void restoreState(Parcelable state, ClassLoader loader) {
327 if (state != null) {
328 Bundle bundle = (Bundle)state;
329 bundle.setClassLoader(loader);
330 Parcelable[] states = bundle.getParcelableArray("states");
331 mSavedState.clear();
332 mFragments.clear();
333 if (states != null) {
334 for (int i=0; i<states.length; i++) {
335 mSavedState.add((Fragment.SavedState)states[i]);
336 }
337 }
338 Iterable<String> keys = bundle.keySet();
339 for (String key: keys) {
340 if (key.startsWith("f")) {
341 int index = Integer.parseInt(key.substring(1));
342 Fragment f = mFragmentManager.getFragment(bundle, key);
343 if (f != null) {
344 while (mFragments.size() <= index) {
345 mFragments.add(null);
346 }
347 f.setMenuVisibility(false);
348 mFragments.set(index, f);
349 } else {
350 Log_OC.w(TAG, "Bad fragment at key " + key);
351 }
352 }
353 }
354 }
355 }
356 */
357 }