Revert changes for files uploading
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / fragment / OCFileListFragment.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.fragment;
19
20 import java.io.File;
21 import java.util.Vector;
22
23 import android.app.Activity;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.os.Bundle;
27 import android.support.v4.widget.SwipeRefreshLayout;
28 import android.view.ContextMenu;
29 import android.view.MenuInflater;
30 import android.view.MenuItem;
31 import android.view.View;
32 import android.widget.AdapterView;
33 import android.widget.AdapterView.AdapterContextMenuInfo;
34 import android.widget.TextView;
35 import android.view.LayoutInflater;
36
37 import com.owncloud.android.R;
38 import com.owncloud.android.datamodel.FileDataStorageManager;
39 import com.owncloud.android.datamodel.OCFile;
40 import com.owncloud.android.files.FileMenuFilter;
41 import com.owncloud.android.lib.common.utils.Log_OC;
42 import com.owncloud.android.ui.activity.FileDisplayActivity;
43 import com.owncloud.android.ui.activity.FolderPickerActivity;
44 import com.owncloud.android.ui.activity.OnEnforceableRefreshListener;
45 import com.owncloud.android.ui.adapter.FileListListAdapter;
46 import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
47 import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
48 import com.owncloud.android.ui.dialog.RenameFileDialogFragment;
49 import com.owncloud.android.ui.preview.PreviewImageFragment;
50 import com.owncloud.android.ui.preview.PreviewMediaFragment;
51 import com.owncloud.android.utils.FileStorageUtils;
52
53 /**
54 * A Fragment that lists all files and folders in a given path.
55 *
56 * TODO refactorize to get rid of direct dependency on FileDisplayActivity
57 *
58 * @author Bartek Przybylski
59 * @author masensio
60 * @author David A. Velasco
61 */
62 public class OCFileListFragment extends ExtendedListFragment {
63
64 private static final String TAG = OCFileListFragment.class.getSimpleName();
65
66 private static final String MY_PACKAGE = OCFileListFragment.class.getPackage() != null ?
67 OCFileListFragment.class.getPackage().getName() : "com.owncloud.android.ui.fragment";
68
69 public final static String ARG_JUST_FOLDERS = MY_PACKAGE + ".JUST_FOLDERS";
70 public final static String ARG_ALLOW_CONTEXTUAL_ACTIONS = MY_PACKAGE + ".ALLOW_CONTEXTUAL";
71
72 private static final String KEY_FILE = MY_PACKAGE + ".extra.FILE";
73
74 private FileFragment.ContainerActivity mContainerActivity;
75
76 private OCFile mFile = null;
77 private FileListListAdapter mAdapter;
78 private View mFooterView;
79
80 private OCFile mTargetFile;
81
82
83 /**
84 * {@inheritDoc}
85 */
86 @Override
87 public void onAttach(Activity activity) {
88 super.onAttach(activity);
89 Log_OC.e(TAG, "onAttach");
90 try {
91 mContainerActivity = (FileFragment.ContainerActivity) activity;
92
93 } catch (ClassCastException e) {
94 throw new ClassCastException(activity.toString() + " must implement " +
95 FileFragment.ContainerActivity.class.getSimpleName());
96 }
97 try {
98 setOnRefreshListener((OnEnforceableRefreshListener) activity);
99
100 } catch (ClassCastException e) {
101 throw new ClassCastException(activity.toString() + " must implement " +
102 SwipeRefreshLayout.OnRefreshListener.class.getSimpleName());
103 }
104 }
105
106
107 @Override
108 public void onDetach() {
109 setOnRefreshListener(null);
110 mContainerActivity = null;
111 super.onDetach();
112 }
113
114 /**
115 * {@inheritDoc}
116 */
117 @Override
118 public void onActivityCreated(Bundle savedInstanceState) {
119 super.onActivityCreated(savedInstanceState);
120 Log_OC.e(TAG, "onActivityCreated() start");
121
122 if (savedInstanceState != null) {
123 mFile = savedInstanceState.getParcelable(KEY_FILE);
124 }
125
126 mFooterView = ((LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(
127 R.layout.list_footer, null, false);
128 setFooterView(mFooterView);
129
130 Bundle args = getArguments();
131 boolean justFolders = (args == null) ? false : args.getBoolean(ARG_JUST_FOLDERS, false);
132 mAdapter = new FileListListAdapter(
133 justFolders,
134 getSherlockActivity(),
135 mContainerActivity
136 );
137 setListAdapter(mAdapter);
138
139 registerForContextMenu(getListView());
140 getListView().setOnCreateContextMenuListener(this);
141 }
142
143 /**
144 * Saves the current listed folder.
145 */
146 @Override
147 public void onSaveInstanceState (Bundle outState) {
148 super.onSaveInstanceState(outState);
149 outState.putParcelable(KEY_FILE, mFile);
150 }
151
152 /**
153 * Call this, when the user presses the up button.
154 *
155 * Tries to move up the current folder one level. If the parent folder was removed from the
156 * database, it continues browsing up until finding an existing folders.
157 *
158 * return Count of folder levels browsed up.
159 */
160 public int onBrowseUp() {
161 OCFile parentDir = null;
162 int moveCount = 0;
163
164 if(mFile != null){
165 FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
166
167 String parentPath = null;
168 if (mFile.getParentId() != FileDataStorageManager.ROOT_PARENT_ID) {
169 parentPath = new File(mFile.getRemotePath()).getParent();
170 parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath :
171 parentPath + OCFile.PATH_SEPARATOR;
172 parentDir = storageManager.getFileByPath(parentPath);
173 moveCount++;
174 } else {
175 parentDir = storageManager.getFileByPath(OCFile.ROOT_PATH);
176 }
177 while (parentDir == null) {
178 parentPath = new File(parentPath).getParent();
179 parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath :
180 parentPath + OCFile.PATH_SEPARATOR;
181 parentDir = storageManager.getFileByPath(parentPath);
182 moveCount++;
183 } // exit is granted because storageManager.getFileByPath("/") never returns null
184 mFile = parentDir;
185
186 listDirectory(mFile);
187
188 onRefresh(false);
189
190 // restore index and top position
191 restoreIndexAndTopPosition();
192
193 } // else - should never happen now
194
195 return moveCount;
196 }
197
198 @Override
199 public void onItemClick(AdapterView<?> l, View v, int position, long id) {
200 OCFile file = (OCFile) mAdapter.getItem(position);
201 if (file != null) {
202 if (file.isFolder()) {
203 // update state and view of this fragment
204 listDirectory(file);
205 // then, notify parent activity to let it update its state and view
206 mContainerActivity.onBrowsedDownTo(file);
207 // save index and top position
208 saveIndexAndTopPosition(position);
209
210 } else { /// Click on a file
211 if (PreviewImageFragment.canBePreviewed(file)) {
212 // preview image - it handles the download, if needed
213 ((FileDisplayActivity)mContainerActivity).startImagePreview(file);
214
215 } else if (file.isDown()) {
216 if (PreviewMediaFragment.canBePreviewed(file)) {
217 // media preview
218 ((FileDisplayActivity)mContainerActivity).startMediaPreview(file, 0, true);
219 } else {
220 mContainerActivity.getFileOperationsHelper().openFile(file);
221 }
222
223 } else {
224 // automatic download, preview on finish
225 ((FileDisplayActivity)mContainerActivity).startDownloadForPreview(file);
226 }
227
228 }
229
230 } else {
231 Log_OC.d(TAG, "Null object in ListAdapter!!");
232 }
233
234 }
235
236 /**
237 * {@inheritDoc}
238 */
239 @Override
240 public void onCreateContextMenu (
241 ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
242 super.onCreateContextMenu(menu, v, menuInfo);
243 Bundle args = getArguments();
244 boolean allowContextualActions =
245 (args == null) ? true : args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, true);
246 if (allowContextualActions) {
247 MenuInflater inflater = getSherlockActivity().getMenuInflater();
248 inflater.inflate(R.menu.file_actions_menu, menu);
249 AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
250 OCFile targetFile = (OCFile) mAdapter.getItem(info.position);
251
252 if (mContainerActivity.getStorageManager() != null) {
253 FileMenuFilter mf = new FileMenuFilter(
254 targetFile,
255 mContainerActivity.getStorageManager().getAccount(),
256 mContainerActivity,
257 getSherlockActivity()
258 );
259 mf.filter(menu);
260 }
261
262 /// TODO break this direct dependency on FileDisplayActivity... if possible
263 MenuItem item = menu.findItem(R.id.action_open_file_with);
264 FileFragment frag = ((FileDisplayActivity)getSherlockActivity()).getSecondFragment();
265 if (frag != null && frag instanceof FileDetailFragment &&
266 frag.getFile().getFileId() == targetFile.getFileId()) {
267 item = menu.findItem(R.id.action_see_details);
268 if (item != null) {
269 item.setVisible(false);
270 item.setEnabled(false);
271 }
272 }
273 }
274 }
275
276
277 /**
278 * {@inhericDoc}
279 */
280 @Override
281 public boolean onContextItemSelected (MenuItem item) {
282 AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
283 mTargetFile = (OCFile) mAdapter.getItem(info.position);
284 switch (item.getItemId()) {
285 case R.id.action_share_file: {
286 mContainerActivity.getFileOperationsHelper().shareFileWithLink(mTargetFile);
287 return true;
288 }
289 case R.id.action_open_file_with: {
290 mContainerActivity.getFileOperationsHelper().openFile(mTargetFile);
291 return true;
292 }
293 case R.id.action_unshare_file: {
294 mContainerActivity.getFileOperationsHelper().unshareFileWithLink(mTargetFile);
295 return true;
296 }
297 case R.id.action_rename_file: {
298 RenameFileDialogFragment dialog = RenameFileDialogFragment.newInstance(mTargetFile);
299 dialog.show(getFragmentManager(), FileDetailFragment.FTAG_RENAME_FILE);
300 return true;
301 }
302 case R.id.action_remove_file: {
303 RemoveFileDialogFragment dialog = RemoveFileDialogFragment.newInstance(mTargetFile);
304 dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
305 return true;
306 }
307 case R.id.action_download_file:
308 case R.id.action_sync_file: {
309 mContainerActivity.getFileOperationsHelper().syncFile(mTargetFile);
310 return true;
311 }
312 case R.id.action_cancel_download:
313 case R.id.action_cancel_upload: {
314 ((FileDisplayActivity)mContainerActivity).cancelTransference(mTargetFile);
315 return true;
316 }
317 case R.id.action_see_details: {
318 mContainerActivity.showDetails(mTargetFile);
319 return true;
320 }
321 case R.id.action_send_file: {
322 // Obtain the file
323 if (!mTargetFile.isDown()) { // Download the file
324 Log_OC.d(TAG, mTargetFile.getRemotePath() + " : File must be downloaded");
325 ((FileDisplayActivity)mContainerActivity).startDownloadForSending(mTargetFile);
326
327 } else {
328 mContainerActivity.getFileOperationsHelper().sendDownloadedFile(mTargetFile);
329 }
330 return true;
331 }
332 case R.id.action_move: {
333 Intent action = new Intent(getActivity(), FolderPickerActivity.class);
334
335 // Pass mTargetFile that contains info of selected file/folder
336 action.putExtra(FolderPickerActivity.EXTRA_FILE, mTargetFile);
337 getActivity().startActivityForResult(action, FileDisplayActivity.ACTION_MOVE_FILES);
338 return true;
339 }
340 default:
341 return super.onContextItemSelected(item);
342 }
343 }
344
345
346 /**
347 * Use this to query the {@link OCFile} that is currently
348 * being displayed by this fragment
349 * @return The currently viewed OCFile
350 */
351 public OCFile getCurrentFile(){
352 return mFile;
353 }
354
355 /**
356 * Calls {@link OCFileListFragment#listDirectory(OCFile)} with a null parameter
357 */
358 public void listDirectory(){
359 listDirectory(null);
360 }
361
362 /**
363 * Lists the given directory on the view. When the input parameter is null,
364 * it will either refresh the last known directory. list the root
365 * if there never was a directory.
366 *
367 * @param directory File to be listed
368 */
369 public void listDirectory(OCFile directory) {
370 FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
371 if (storageManager != null) {
372
373 // Check input parameters for null
374 if(directory == null){
375 if(mFile != null){
376 directory = mFile;
377 } else {
378 directory = storageManager.getFileByPath("/");
379 if (directory == null) return; // no files, wait for sync
380 }
381 }
382
383
384 // If that's not a directory -> List its parent
385 if(!directory.isFolder()){
386 Log_OC.w(TAG, "You see, that is not a directory -> " + directory.toString());
387 directory = storageManager.getFileById(directory.getParentId());
388 }
389
390 mAdapter.swapDirectory(directory, storageManager);
391 if (mFile == null || !mFile.equals(directory)) {
392 mList.setSelectionFromTop(0, 0);
393 }
394 mFile = directory;
395
396 // Update Footer
397 TextView footerText = (TextView) mFooterView.findViewById(R.id.footerText);
398 Log_OC.d("footer", String.valueOf(System.currentTimeMillis()));
399 footerText.setText(generateFooterText(directory));
400 Log_OC.d("footer", String.valueOf(System.currentTimeMillis()));
401 }
402 }
403
404 private String generateFooterText(OCFile directory) {
405 Integer files = 0;
406 Integer folders = 0;
407
408 FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
409 Vector<OCFile> mFiles = storageManager.getFolderContent(mFile);
410
411 for (OCFile ocFile : mFiles) {
412 if (ocFile.isFolder()) {
413 folders++;
414 } else {
415 files++;
416 }
417 }
418
419 String output = "";
420
421 if (files > 0){
422 if (files == 1) {
423 output = output + files.toString() + " " + getResources().getString(R.string.file_list_file);
424 } else {
425 output = output + files.toString() + " " + getResources().getString(R.string.file_list_files);
426 }
427 }
428 if (folders > 0 && files > 0){
429 output = output + ", ";
430 }
431 if (folders == 1) {
432 output = output + folders.toString() + " " + getResources().getString(R.string.file_list_folder);
433 } else if (folders > 1) {
434 output = output + folders.toString() + " " + getResources().getString(R.string.file_list_folders);
435 }
436
437 return output;
438 }
439
440 public void sortByName(boolean descending) {
441 mAdapter.setSortOrder(FileStorageUtils.SORT_NAME, descending);
442 }
443
444 public void sortByDate(boolean descending) {
445 mAdapter.setSortOrder(FileStorageUtils.SORT_DATE, descending);
446 }
447
448 public void sortBySize(boolean descending) {
449 mAdapter.setSortOrder(FileStorageUtils.SORT_SIZE, descending);
450 }
451
452 }