378fe05d7604697d453628b57a55b98862389e84
[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 import java.io.File;
21 import java.util.Collections;
22 import java.util.Comparator;
23 import java.util.Vector;
24
25 import android.accounts.Account;
26 import android.content.Context;
27 import android.content.SharedPreferences;
28 import android.preference.PreferenceManager;
29 import android.view.LayoutInflater;
30 import android.view.View;
31 import android.view.ViewGroup;
32 import android.widget.BaseAdapter;
33 import android.widget.ImageView;
34 import android.widget.ListAdapter;
35 import android.widget.ListView;
36 import android.widget.TextView;
37
38 import com.owncloud.android.R;
39 import com.owncloud.android.authentication.AccountUtils;
40 import com.owncloud.android.datamodel.AlphanumComparator;
41 import com.owncloud.android.datamodel.FileDataStorageManager;
42 import com.owncloud.android.datamodel.OCFile;
43 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
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 import com.owncloud.android.utils.Log_OC;
49
50
51 /**
52 * This Adapter populates a ListView with all files and folders in an ownCloud
53 * instance.
54 *
55 * @author Bartek Przybylski
56 *
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 private String sortOrder;
70 private Boolean sortAscending;
71 private SharedPreferences appPreferences;
72
73 public FileListListAdapter(
74 boolean justFolders,
75 Context context,
76 ComponentsGetter transferServiceGetter
77 ) {
78 mJustFolders = justFolders;
79 mContext = context;
80 mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext);
81 mTransferServiceGetter = transferServiceGetter;
82
83 appPreferences = PreferenceManager
84 .getDefaultSharedPreferences(mContext);
85
86 // Read sorting order, default to sort by name ascending
87 sortOrder = appPreferences
88 .getString("sortOrder", "name");
89 sortAscending = appPreferences.getBoolean("sortAscending", true);
90
91 }
92
93 @Override
94 public boolean areAllItemsEnabled() {
95 return true;
96 }
97
98 @Override
99 public boolean isEnabled(int position) {
100 return true;
101 }
102
103 @Override
104 public int getCount() {
105 return mFiles != null ? mFiles.size() : 0;
106 }
107
108 @Override
109 public Object getItem(int position) {
110 if (mFiles == null || mFiles.size() <= position)
111 return null;
112 return mFiles.get(position);
113 }
114
115 @Override
116 public long getItemId(int position) {
117 if (mFiles == null || mFiles.size() <= position)
118 return 0;
119 return mFiles.get(position).getFileId();
120 }
121
122 @Override
123 public int getItemViewType(int position) {
124 return 0;
125 }
126
127 @Override
128 public View getView(int position, View convertView, ViewGroup parent) {
129 View view = convertView;
130 if (view == null) {
131 LayoutInflater inflator = (LayoutInflater) mContext
132 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
133 view = inflator.inflate(R.layout.list_item, null);
134 }
135
136 if (mFiles != null && mFiles.size() > position) {
137 OCFile file = mFiles.get(position);
138 TextView fileName = (TextView) view.findViewById(R.id.Filename);
139 String name = file.getFileName();
140
141 fileName.setText(name);
142 ImageView fileIcon = (ImageView) view.findViewById(R.id.imageView1);
143 ImageView sharedIconV = (ImageView) view.findViewById(R.id.sharedIcon);
144 ImageView sharedWithMeIconV = (ImageView) view.findViewById(R.id.sharedWithMeIcon);
145 sharedWithMeIconV.setVisibility(View.GONE);
146
147 ImageView localStateView = (ImageView) view.findViewById(R.id.imageView2);
148 localStateView.bringToFront();
149 FileDownloaderBinder downloaderBinder = mTransferServiceGetter.getFileDownloaderBinder();
150 FileUploaderBinder uploaderBinder = mTransferServiceGetter.getFileUploaderBinder();
151 if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file)) {
152 localStateView.setImageResource(R.drawable.downloading_file_indicator);
153 localStateView.setVisibility(View.VISIBLE);
154 } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, file)) {
155 localStateView.setImageResource(R.drawable.uploading_file_indicator);
156 localStateView.setVisibility(View.VISIBLE);
157 } else if (file.isDown()) {
158 localStateView.setImageResource(R.drawable.local_file_indicator);
159 localStateView.setVisibility(View.VISIBLE);
160 } else {
161 localStateView.setVisibility(View.INVISIBLE);
162 }
163
164 TextView fileSizeV = (TextView) view.findViewById(R.id.file_size);
165 TextView lastModV = (TextView) view.findViewById(R.id.last_mod);
166 ImageView checkBoxV = (ImageView) view.findViewById(R.id.custom_checkbox);
167
168 if (!file.isFolder()) {
169 fileSizeV.setVisibility(View.VISIBLE);
170 fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));
171 lastModV.setVisibility(View.VISIBLE);
172 lastModV.setText(DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp()));
173 // this if-else is needed even thoe fav icon is visible by default
174 // because android reuses views in listview
175 if (!file.keepInSync()) {
176 view.findViewById(R.id.imageView3).setVisibility(View.GONE);
177 } else {
178 view.findViewById(R.id.imageView3).setVisibility(View.VISIBLE);
179 }
180
181 ListView parentList = (ListView)parent;
182 if (parentList.getChoiceMode() == ListView.CHOICE_MODE_NONE) {
183 checkBoxV.setVisibility(View.GONE);
184 } else {
185 if (parentList.isItemChecked(position)) {
186 checkBoxV.setImageResource(android.R.drawable.checkbox_on_background);
187 } else {
188 checkBoxV.setImageResource(android.R.drawable.checkbox_off_background);
189 }
190 checkBoxV.setVisibility(View.VISIBLE);
191 }
192
193 fileIcon.setImageResource(DisplayUtils.getResourceId(file.getMimetype(), file.getFileName()));
194
195 if (checkIfFileIsSharedWithMe(file)) {
196 sharedWithMeIconV.setVisibility(View.VISIBLE);
197 }
198 }
199 else {
200 if (FileStorageUtils.getDefaultSavePathFor(mAccount.name, file) != null){
201 fileSizeV.setVisibility(View.VISIBLE);
202 fileSizeV.setText(getFolderSizeHuman(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file)));
203 } else {
204 fileSizeV.setVisibility(View.INVISIBLE);
205 }
206
207 lastModV.setVisibility(View.VISIBLE);
208 lastModV.setText(DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp()));
209 checkBoxV.setVisibility(View.GONE);
210 view.findViewById(R.id.imageView3).setVisibility(View.GONE);
211
212 if (checkIfFileIsSharedWithMe(file)) {
213 fileIcon.setImageResource(R.drawable.shared_with_me_folder);
214 sharedWithMeIconV.setVisibility(View.VISIBLE);
215 } else {
216 fileIcon.setImageResource(DisplayUtils.getResourceId(file.getMimetype(), file.getFileName()));
217 }
218
219 // If folder is sharedByLink, icon folder must be changed to
220 // folder-public one
221 if (file.isShareByLink()) {
222 fileIcon.setImageResource(R.drawable.folder_public);
223 }
224 }
225
226 if (file.isShareByLink()) {
227 sharedIconV.setVisibility(View.VISIBLE);
228 } else {
229 sharedIconV.setVisibility(View.GONE);
230 }
231 }
232
233 return view;
234 }
235
236 /**
237 * Local Folder size in human readable format
238 * @param path String
239 * @return Size in human readable format
240 */
241 private String getFolderSizeHuman(String path) {
242
243 File dir = new File(path);
244
245 if(dir.exists()) {
246 long bytes = getFolderSize(dir);
247 if (bytes < 1024) return bytes + " B";
248 int exp = (int) (Math.log(bytes) / Math.log(1024));
249 String pre = ("KMGTPE").charAt(exp-1) + "";
250
251 return String.format("%.1f %sB", bytes / Math.pow(1024, exp), pre);
252 }
253
254 return "0 B";
255 }
256
257 /**
258 * Local Folder size
259 * @param dir File
260 * @return Size in bytes
261 */
262 private long getFolderSize(File dir) {
263 if (dir.exists()) {
264 long result = 0;
265 File[] fileList = dir.listFiles();
266 for(int i = 0; i < fileList.length; i++) {
267 if(fileList[i].isDirectory()) {
268 result += getFolderSize(fileList[i]);
269 } else {
270 result += fileList[i].length();
271 }
272 }
273 return result;
274 }
275 return 0;
276 }
277
278 @Override
279 public int getViewTypeCount() {
280 return 1;
281 }
282
283 @Override
284 public boolean hasStableIds() {
285 return true;
286 }
287
288 @Override
289 public boolean isEmpty() {
290 return (mFiles == null || mFiles.isEmpty());
291 }
292
293 /**
294 * Change the adapted directory for a new one
295 * @param directory New file to adapt. Can be NULL, meaning "no content to adapt".
296 * @param updatedStorageManager Optional updated storage manager; used to replace mStorageManager if is different (and not NULL)
297 */
298 public void swapDirectory(OCFile directory, FileDataStorageManager updatedStorageManager) {
299 mFile = directory;
300 if (updatedStorageManager != null && updatedStorageManager != mStorageManager) {
301 mStorageManager = updatedStorageManager;
302 mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext);
303 }
304 if (mStorageManager != null) {
305 mFiles = mStorageManager.getFolderContent(mFile);
306 if (mJustFolders) {
307 mFiles = getFolders(mFiles);
308 }
309 } else {
310 mFiles = null;
311 }
312
313 sortDirectory();
314 }
315
316 /**
317 * Sorts all filenames, regarding last user decision
318 */
319 private void sortDirectory(){
320 if (sortOrder.equals("name")){
321 sortByName(sortAscending);
322 } else if (sortOrder.equals("size")){
323 sortBySize(sortAscending);
324 } else if (sortOrder.equals("date")){
325 sortByDate(sortAscending);
326 }
327
328 notifyDataSetChanged();
329 }
330
331
332 /**
333 * Filter for getting only the folders
334 * @param files
335 * @return Vector<OCFile>
336 */
337 public Vector<OCFile> getFolders(Vector<OCFile> files) {
338 Vector<OCFile> ret = new Vector<OCFile>();
339 OCFile current = null;
340 for (int i=0; i<files.size(); i++) {
341 current = files.get(i);
342 if (current.isFolder()) {
343 ret.add(current);
344 }
345 }
346 return ret;
347 }
348
349
350 /**
351 * Check if parent folder does not include 'S' permission and if file/folder
352 * is shared with me
353 *
354 * @param file: OCFile
355 * @return boolean: True if it is shared with me and false if it is not
356 */
357 private boolean checkIfFileIsSharedWithMe(OCFile file) {
358 return (mFile.getPermissions() != null && !mFile.getPermissions().contains(PERMISSION_SHARED_WITH_ME)
359 && file.getPermissions() != null && file.getPermissions().contains(PERMISSION_SHARED_WITH_ME));
360 }
361
362 /**
363 * Sorts list by Date
364 * @param sortAscending true: ascending, false: descending
365 */
366 private void sortByDate(boolean sortAscending){
367 final Integer val;
368 if (sortAscending){
369 val = 1;
370 } else {
371 val = -1;
372 }
373
374 Collections.sort(mFiles, new Comparator<OCFile>() {
375 public int compare(OCFile o1, OCFile o2) {
376 if (o1.isFolder() && o2.isFolder()) {
377 return val * Long.compare(o1.getModificationTimestamp(), o2.getModificationTimestamp());
378 }
379 else if (o1.isFolder()) {
380 return -1;
381 } else if (o2.isFolder()) {
382 return 1;
383 } else if (o1.getModificationTimestamp() == 0 || o2.getModificationTimestamp() == 0){
384 return 0;
385 } else {
386 return val * Long.compare(o1.getModificationTimestamp(), o2.getModificationTimestamp());
387 }
388 }
389 });
390 }
391
392 /**
393 * Sorts list by Size
394 * @param sortAscending true: ascending, false: descending
395 */
396 private void sortBySize(boolean sortAscending){
397 final Integer val;
398 if (sortAscending){
399 val = 1;
400 } else {
401 val = -1;
402 }
403
404 Collections.sort(mFiles, new Comparator<OCFile>() {
405 public int compare(OCFile o1, OCFile o2) {
406 if (o1.isFolder() && o2.isFolder()) {
407 return val * Long.compare(getFolderSize(new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, o1))),
408 getFolderSize(new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, o2))));
409 }
410 else if (o1.isFolder()) {
411 return -1;
412 } else if (o2.isFolder()) {
413 return 1;
414 } else if (o1.getFileLength() == 0 || o2.getFileLength() == 0){
415 return 0;
416 } else {
417 return val * Long.compare(o1.getFileLength(), o2.getFileLength());
418 }
419 }
420 });
421 }
422
423 /**
424 * Sorts list by Name
425 * @param sortAscending true: ascending, false: descending
426 */
427 private void sortByName(boolean sortAscending){
428 final Integer val;
429 if (sortAscending){
430 val = 1;
431 } else {
432 val = -1;
433 }
434
435 Collections.sort(mFiles, new Comparator<OCFile>() {
436 public int compare(OCFile o1, OCFile o2) {
437 if (o1.isFolder() && o2.isFolder()) {
438 return val * o1.getRemotePath().toLowerCase().compareTo(o2.getRemotePath().toLowerCase());
439 } else if (o1.isFolder()) {
440 return -1;
441 } else if (o2.isFolder()) {
442 return 1;
443 }
444 return val * new AlphanumComparator().compare(o1, o2);
445 }
446 });
447 }
448
449 public void setSortOrder(String order, boolean ascending) {
450 SharedPreferences.Editor editor = appPreferences.edit();
451 editor.putString("sortOrder", order);
452 editor.putBoolean("sortAscending", ascending);
453 editor.commit();
454
455 sortOrder = order;
456 sortAscending = ascending;
457
458 sortDirectory();
459 }
460 }