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