d809f141669baf234f0892e4816eabb3feb96a8c
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / adapter / FileListListAdapter.java
1 /* ownCloud Android client application
2 * Copyright (C) 2011 Bartek Przybylski
3 * Copyright (C) 2012-2015 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 package com.owncloud.android.ui.adapter;
19
20
21 import java.io.File;
22 import java.util.Vector;
23
24 import android.accounts.Account;
25 import android.content.Context;
26 import android.content.SharedPreferences;
27 import android.graphics.Bitmap;
28 import android.preference.PreferenceManager;
29 import android.text.format.DateUtils;
30 import android.view.LayoutInflater;
31 import android.view.View;
32 import android.view.ViewGroup;
33 import android.widget.BaseAdapter;
34 import android.widget.GridView;
35 import android.widget.ImageView;
36 import android.widget.ListAdapter;
37 import android.widget.TextView;
38
39 import com.owncloud.android.R;
40 import com.owncloud.android.authentication.AccountUtils;
41 import com.owncloud.android.datamodel.FileDataStorageManager;
42 import com.owncloud.android.datamodel.OCFile;
43 import com.owncloud.android.datamodel.ThumbnailsCacheManager;
44 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
45 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
46 import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
47 import com.owncloud.android.ui.activity.ComponentsGetter;
48 import com.owncloud.android.utils.DisplayUtils;
49 import com.owncloud.android.utils.FileStorageUtils;
50
51
52 /**
53 * This Adapter populates a ListView with all files and folders in an ownCloud
54 * instance.
55 *
56 * @author Bartek Przybylski
57 * @author Tobias Kaminsky
58 * @author David A. Velasco
59 */
60 public class FileListListAdapter extends BaseAdapter implements ListAdapter {
61 private final static String PERMISSION_SHARED_WITH_ME = "S";
62
63 private Context mContext;
64 private OCFile mFile = null;
65 private Vector<OCFile> mFiles = null;
66 private Vector<OCFile> mFilesOrig = new Vector<OCFile>();
67 private boolean mJustFolders;
68
69 private FileDataStorageManager mStorageManager;
70 private Account mAccount;
71 private ComponentsGetter mTransferServiceGetter;
72
73 private enum ViewType {LIST_ITEM, GRID_IMAGE, GRID_ITEM };
74
75 private SharedPreferences mAppPreferences;
76
77 public FileListListAdapter(
78 boolean justFolders,
79 Context context,
80 ComponentsGetter transferServiceGetter
81 ) {
82
83 mJustFolders = justFolders;
84 mContext = context;
85 mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext);
86 mTransferServiceGetter = transferServiceGetter;
87
88 mAppPreferences = PreferenceManager
89 .getDefaultSharedPreferences(mContext);
90
91 // Read sorting order, default to sort by name ascending
92 FileStorageUtils.mSortOrder = mAppPreferences.getInt("sortOrder", 0);
93 FileStorageUtils.mSortAscending = mAppPreferences.getBoolean("sortAscending", true);
94
95
96 // initialise thumbnails cache on background thread
97 new ThumbnailsCacheManager.InitDiskCacheTask().execute();
98 }
99
100 @Override
101 public boolean areAllItemsEnabled() {
102 return true;
103 }
104
105 @Override
106 public boolean isEnabled(int position) {
107 return true;
108 }
109
110 @Override
111 public int getCount() {
112 return mFiles != null ? mFiles.size() : 0;
113 }
114
115 @Override
116 public Object getItem(int position) {
117 if (mFiles == null || mFiles.size() <= position)
118 return null;
119 return mFiles.get(position);
120 }
121
122 @Override
123 public long getItemId(int position) {
124 if (mFiles == null || mFiles.size() <= position)
125 return 0;
126 return mFiles.get(position).getFileId();
127 }
128
129 @Override
130 public int getItemViewType(int position) {
131 return 0;
132 }
133
134 @Override
135 public View getView(int position, View convertView, ViewGroup parent) {
136
137 boolean fileView = DisplayUtils.decideViewLayout(mFiles);
138
139 View view = convertView;
140 OCFile file = null;
141 LayoutInflater inflator = (LayoutInflater) mContext
142 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
143
144 if (mFiles != null && mFiles.size() > position) {
145 file = mFiles.get(position);
146 }
147
148 // Find out which layout should be displayed
149 ViewType viewType;
150 if (!fileView){
151 viewType = ViewType.LIST_ITEM;
152 } else if (file.isImage()){
153 viewType = ViewType.GRID_IMAGE;
154 } else {
155 viewType = ViewType.GRID_ITEM;
156 }
157
158 // Create View
159 switch (viewType){
160 case GRID_IMAGE:
161 view = inflator.inflate(R.layout.grid_image, null);
162 break;
163 case GRID_ITEM:
164 view = inflator.inflate(R.layout.grid_item, null);
165 break;
166 case LIST_ITEM:
167 view = inflator.inflate(R.layout.list_item, null);
168 break;
169 }
170
171 view.invalidate();
172
173 if (file != null){
174
175 ImageView fileIcon = (ImageView) view.findViewById(R.id.thumbnail);
176 fileIcon.setTag(file.getFileId());
177 TextView fileName;
178 String name;
179
180 switch (viewType){
181 case LIST_ITEM:
182 TextView fileSizeV = (TextView) view.findViewById(R.id.file_size);
183 TextView lastModV = (TextView) view.findViewById(R.id.last_mod);
184 ImageView checkBoxV = (ImageView) view.findViewById(R.id.custom_checkbox);
185
186 lastModV.setVisibility(View.VISIBLE);
187 lastModV.setText(showRelativeTimestamp(file));
188
189 checkBoxV.setVisibility(View.GONE);
190
191 fileSizeV.setVisibility(View.VISIBLE);
192 fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));
193
194 if (!file.isFolder()) {
195 GridView parentList = (GridView)parent;
196 if (parentList.getChoiceMode() == GridView.CHOICE_MODE_NONE) {
197 checkBoxV.setVisibility(View.GONE);
198 } else {
199 if (parentList.isItemChecked(position)) {
200 checkBoxV.setImageResource(android.R.drawable.checkbox_on_background);
201 } else {
202 checkBoxV.setImageResource(android.R.drawable.checkbox_off_background);
203 }
204 checkBoxV.setVisibility(View.VISIBLE);
205 }
206
207 } else { //Folder
208 fileSizeV.setVisibility(View.INVISIBLE);
209 }
210
211 case GRID_ITEM:
212 // filename
213 fileName = (TextView) view.findViewById(R.id.Filename);
214 name = file.getFileName();
215 fileName.setText(name);
216
217 case GRID_IMAGE:
218 // sharedIcon
219 ImageView sharedIconV = (ImageView) view.findViewById(R.id.sharedIcon);
220 if (file.isShareByLink()) {
221 sharedIconV.setVisibility(View.VISIBLE);
222 sharedIconV.bringToFront();
223 } else {
224 sharedIconV.setVisibility(View.GONE);
225 }
226
227 // local state
228 ImageView localStateView = (ImageView) view.findViewById(R.id.localFileIndicator);
229 localStateView.bringToFront();
230 FileDownloaderBinder downloaderBinder = mTransferServiceGetter.getFileDownloaderBinder();
231 FileUploaderBinder uploaderBinder = mTransferServiceGetter.getFileUploaderBinder();
232 boolean downloading = (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file));
233 OperationsServiceBinder opsBinder = mTransferServiceGetter.getOperationsServiceBinder();
234 downloading |= (opsBinder != null && opsBinder.isSynchronizing(mAccount, file.getRemotePath()));
235 if (downloading) {
236 localStateView.setImageResource(R.drawable.downloading_file_indicator);
237 localStateView.setVisibility(View.VISIBLE);
238 } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, file)) {
239 localStateView.setImageResource(R.drawable.uploading_file_indicator);
240 localStateView.setVisibility(View.VISIBLE);
241 } else if (file.isDown()) {
242 localStateView.setImageResource(R.drawable.local_file_indicator);
243 localStateView.setVisibility(View.VISIBLE);
244 } else {
245 localStateView.setVisibility(View.INVISIBLE);
246 }
247
248 // share with me icon
249 if (!file.isFolder()) {
250 ImageView sharedWithMeIconV = (ImageView) view.findViewById(R.id.sharedWithMeIcon);
251 sharedWithMeIconV.bringToFront();
252 if (checkIfFileIsSharedWithMe(file)) {
253 sharedWithMeIconV.setVisibility(View.VISIBLE);
254 } else {
255 sharedWithMeIconV.setVisibility(View.GONE);
256 }
257 }
258
259 break;
260 }
261
262 // For all Views
263
264 // this if-else is needed even though favorite icon is visible by default
265 // because android reuses views in listview
266 if (!file.keepInSync()) {
267 view.findViewById(R.id.favoriteIcon).setVisibility(View.GONE);
268 } else {
269 view.findViewById(R.id.favoriteIcon).setVisibility(View.VISIBLE);
270 }
271
272 // No Folder
273 if (!file.isFolder()) {
274 if (file.isImage() && file.getRemoteId() != null){
275 // Thumbnail in Cache?
276 Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(
277 String.valueOf(file.getRemoteId())
278 );
279 if (thumbnail != null && !file.needsUpdateThumbnail()){
280 fileIcon.setImageBitmap(thumbnail);
281 } else {
282 // generate new Thumbnail
283 if (ThumbnailsCacheManager.cancelPotentialWork(file, fileIcon)) {
284 final ThumbnailsCacheManager.ThumbnailGenerationTask task =
285 new ThumbnailsCacheManager.ThumbnailGenerationTask(
286 fileIcon, mStorageManager, mAccount
287 );
288 if (thumbnail == null) {
289 thumbnail = ThumbnailsCacheManager.mDefaultImg;
290 }
291 final ThumbnailsCacheManager.AsyncDrawable asyncDrawable =
292 new ThumbnailsCacheManager.AsyncDrawable(
293 mContext.getResources(),
294 thumbnail,
295 task
296 );
297 fileIcon.setImageDrawable(asyncDrawable);
298 task.execute(file);
299 }
300 }
301 } else {
302 fileIcon.setImageResource(DisplayUtils.getFileTypeIconId(file.getMimetype(), file.getFileName()));
303 }
304 } else {
305 // Folder
306 if (checkIfFileIsSharedWithMe(file)) {
307 fileIcon.setImageResource(R.drawable.shared_with_me_folder);
308 } else if (file.isShareByLink()) {
309 // If folder is sharedByLink, icon folder must be changed to
310 // folder-public one
311 fileIcon.setImageResource(R.drawable.folder_public);
312 } else {
313 fileIcon.setImageResource(
314 DisplayUtils.getFileTypeIconId(file.getMimetype(), file.getFileName())
315 );
316 }
317 }
318 }
319
320 return view;
321 }
322
323 /**
324 * Local Folder size in human readable format
325 *
326 * @param path
327 * String
328 * @return Size in human readable format
329 */
330 private String getFolderSizeHuman(String path) {
331
332 File dir = new File(path);
333
334 if (dir.exists()) {
335 long bytes = FileStorageUtils.getFolderSize(dir);
336 return DisplayUtils.bytesToHumanReadable(bytes);
337 }
338
339 return "0 B";
340 }
341
342 /**
343 * Local Folder size
344 * @param dir File
345 * @return Size in bytes
346 */
347 private long getFolderSize(File dir) {
348 if (dir.exists()) {
349 long result = 0;
350 File[] fileList = dir.listFiles();
351 for(int i = 0; i < fileList.length; i++) {
352 if(fileList[i].isDirectory()) {
353 result += getFolderSize(fileList[i]);
354 } else {
355 result += fileList[i].length();
356 }
357 }
358 return result;
359 }
360 return 0;
361 }
362
363 @Override
364 public int getViewTypeCount() {
365 return 1;
366 }
367
368 @Override
369 public boolean hasStableIds() {
370 return true;
371 }
372
373 @Override
374 public boolean isEmpty() {
375 return (mFiles == null || mFiles.isEmpty());
376 }
377
378 /**
379 * Change the adapted directory for a new one
380 * @param directory New file to adapt. Can be NULL, meaning
381 * "no content to adapt".
382 * @param updatedStorageManager Optional updated storage manager; used to replace
383 * mStorageManager if is different (and not NULL)
384 */
385 public void swapDirectory(OCFile directory, FileDataStorageManager updatedStorageManager) {
386 mFile = directory;
387 if (updatedStorageManager != null && updatedStorageManager != mStorageManager) {
388 mStorageManager = updatedStorageManager;
389 mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext);
390 }
391 if (mStorageManager != null) {
392 mFiles = mStorageManager.getFolderContent(mFile);
393 mFilesOrig.clear();
394 mFilesOrig.addAll(mFiles);
395
396 if (mJustFolders) {
397 mFiles = getFolders(mFiles);
398 }
399 } else {
400 mFiles = null;
401 }
402
403 mFiles = FileStorageUtils.sortFolder(mFiles);
404 notifyDataSetChanged();
405 }
406
407
408 /**
409 * Filter for getting only the folders
410 * @param files
411 * @return Vector<OCFile>
412 */
413 public Vector<OCFile> getFolders(Vector<OCFile> files) {
414 Vector<OCFile> ret = new Vector<OCFile>();
415 OCFile current = null;
416 for (int i=0; i<files.size(); i++) {
417 current = files.get(i);
418 if (current.isFolder()) {
419 ret.add(current);
420 }
421 }
422 return ret;
423 }
424
425
426 /**
427 * Check if parent folder does not include 'S' permission and if file/folder
428 * is shared with me
429 *
430 * @param file: OCFile
431 * @return boolean: True if it is shared with me and false if it is not
432 */
433 private boolean checkIfFileIsSharedWithMe(OCFile file) {
434 return (mFile.getPermissions() != null
435 && !mFile.getPermissions().contains(PERMISSION_SHARED_WITH_ME)
436 && file.getPermissions() != null
437 && file.getPermissions().contains(PERMISSION_SHARED_WITH_ME));
438 }
439
440 public void setSortOrder(Integer order, boolean ascending) {
441 SharedPreferences.Editor editor = mAppPreferences.edit();
442 editor.putInt("sortOrder", order);
443 editor.putBoolean("sortAscending", ascending);
444 editor.commit();
445
446 FileStorageUtils.mSortOrder = order;
447 FileStorageUtils.mSortAscending = ascending;
448
449
450 mFiles = FileStorageUtils.sortFolder(mFiles);
451 notifyDataSetChanged();
452
453 }
454
455 private CharSequence showRelativeTimestamp(OCFile file){
456 return DisplayUtils.getRelativeDateTimeString(mContext, file.getModificationTimestamp(),
457 DateUtils.SECOND_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, 0);
458 }
459 }