From: jabarros Date: Thu, 9 Oct 2014 15:26:02 +0000 (+0200) Subject: Merge branch 'sortingFiles' of https://github.com/tobiasKaminsky/android into sorting... X-Git-Tag: oc-android-1.7.0_signed~134^2~5 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/7d9fc6857e1d534c1930b94b6063f1e21a827e9b?hp=-c Merge branch 'sortingFiles' of https://github.com/tobiasKaminsky/android into sorting_files Conflicts: res/menu/main_menu.xml src/com/owncloud/android/ui/activity/FileDisplayActivity.java src/com/owncloud/android/ui/adapter/FileListListAdapter.java --- 7d9fc6857e1d534c1930b94b6063f1e21a827e9b diff --combined res/menu/main_menu.xml index 1df273ea,506ed15c..6e64fcf7 --- a/res/menu/main_menu.xml +++ b/res/menu/main_menu.xml @@@ -44,11 -44,10 +44,16 @@@ android:showAsAction="never" android:title="@string/actionbar_settings"/> ++ diff --combined res/values-de/strings.xml index 0b536c10,3dd6a5a7..e8f43195 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@@ -11,6 -11,13 +11,13 @@@ Einstellungen Details Senden + Sortieren + Sortieren nach + + A-Z + Neu - Alt + Groß - Klein + Allgemein Mehr Konten @@@ -264,18 -271,14 +271,18 @@@ Konten Konto hinzufügen Die gesicherte Verbindung wird auf eine unsichere Route weitergeleitet. - Authentifizierung benötigt + Protokolle + Verlauf senden + Protokolle der ownCloud-Android-App + Daten werden geladen … + Legitimierung benötigt Falsches Passwort Verschieben Nichts vorhanden. Du kannst einen Ordner hinzufügen! Auswählen Verschieben nicht möglich. Prüfe, dass die Datei existiert Es ist nicht möglich einen Ordner eine Ebene tiefer zu verschieben - Die Datei existiert bereits im Zielordner + Die Datei ist bereits im Zielordner vorhanden Es ist ein Fehler beim Verschieben dieser Datei oder Ordners aufgetreten. zum Datei verschieben diff --combined res/values/strings.xml index 4c7cf34d,c4bea810..4c5f57b0 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@@ -12,6 -12,13 +12,13 @@@ Settings Details Send + Sort + Sort by + + A-Z + Newest - Oldest + Biggest - Smallest + General More Accounts @@@ -285,11 -292,6 +292,11 @@@ Add account Secure connection is redirected through an unsecured route. + Logs + Send History + ownCloud Android app logs + Loading data... + Authentication required Wrong password Move diff --combined src/com/owncloud/android/datamodel/OCFile.java index c3284fc0,03ec1632..7ef9bc55 --- a/src/com/owncloud/android/datamodel/OCFile.java +++ b/src/com/owncloud/android/datamodel/OCFile.java @@@ -20,7 -20,7 +20,7 @@@ package com.owncloud.android.datamodel import java.io.File; -import com.owncloud.android.utils.Log_OC; +import com.owncloud.android.lib.common.utils.Log_OC; import android.os.Parcel; @@@ -68,8 -68,6 +68,8 @@@ public class OCFile implements Parcelab private String mPermissions; private String mRemoteId; + private boolean mNeedsUpdateThumbnail; + /** * Create new {@link OCFile} with given path. @@@ -111,8 -109,6 +111,8 @@@ mPublicLink = source.readString(); mPermissions = source.readString(); mRemoteId = source.readString(); + mNeedsUpdateThumbnail = source.readInt() == 0; + } @Override @@@ -135,7 -131,6 +135,7 @@@ dest.writeString(mPublicLink); dest.writeString(mPermissions); dest.writeString(mRemoteId); + dest.writeInt(mNeedsUpdateThumbnail ? 1 : 0); } /** @@@ -348,7 -343,6 +348,7 @@@ mPublicLink = null; mPermissions = null; mRemoteId = null; + mNeedsUpdateThumbnail = false; } /** @@@ -414,14 -408,6 +414,14 @@@ return mNeedsUpdating; } + public boolean needsUpdateThumbnail() { + return mNeedsUpdateThumbnail; + } + + public void setNeedsUpdateThumbnail(boolean needsUpdateThumbnail) { + this.mNeedsUpdateThumbnail = needsUpdateThumbnail; + } + public long getLastSyncDateForProperties() { return mLastSyncDateForProperties; } @@@ -460,7 -446,7 +460,7 @@@ } else if (another.isFolder()) { return 1; } - return getRemotePath().toLowerCase().compareTo(another.getRemotePath().toLowerCase()); + return new AlphanumComparator().compare(this, another); } @Override diff --combined src/com/owncloud/android/ui/activity/FileDisplayActivity.java index 21472fd1,2d10ab94..8560ddbb --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@@ -21,6 -21,8 +21,6 @@@ package com.owncloud.android.ui.activit import java.io.File; import java.io.IOException; -import org.apache.commons.httpclient.methods.PostMethod; - import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AuthenticatorException; @@@ -48,7 -50,8 +48,6 @@@ import android.provider.MediaStore import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; -import android.support.v4.widget.SwipeRefreshLayout; --import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; @@@ -61,7 -64,6 +60,7 @@@ import com.actionbarsherlock.view.Menu import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.actionbarsherlock.view.Window; +import com.owncloud.android.BuildConfig; import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.datamodel.OCFile; @@@ -78,7 -80,6 +77,7 @@@ import com.owncloud.android.lib.common. import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; +import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.operations.CreateFolderOperation; import com.owncloud.android.operations.CreateShareOperation; import com.owncloud.android.operations.MoveFileOperation; @@@ -101,6 -102,7 +100,6 @@@ import com.owncloud.android.ui.preview. import com.owncloud.android.ui.preview.PreviewVideoActivity; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.ErrorMessageAdapter; -import com.owncloud.android.utils.Log_OC; /** @@@ -112,7 -114,7 +111,7 @@@ public class FileDisplayActivity extends HookActivity implements FileFragment.ContainerActivity, OnNavigationListener, -OnSslUntrustedCertListener, SwipeRefreshLayout.OnRefreshListener { +OnSslUntrustedCertListener, OnEnforceableRefreshListener { private ArrayAdapter mDirectories; @@@ -151,7 -153,7 +150,7 @@@ private String DIALOG_UNTRUSTED_CERT; private OCFile mWaitingToSend; - + @Override protected void onCreate(Bundle savedInstanceState) { Log_OC.d(TAG, "onCreate() start"); @@@ -249,7 -251,7 +248,7 @@@ Log_OC.e(TAG, "Initializing Fragments in onAccountChanged.."); initFragmentsWithFile(); if (file.isFolder()) { - startSyncFolderOperation(file); + startSyncFolderOperation(file, false); } } else { @@@ -290,7 -292,7 +289,7 @@@ if (listOfFiles != null) { listOfFiles.listDirectory(getCurrentDir()); } else { - Log.e(TAG, "Still have a chance to lose the initializacion of list fragment >("); + Log_OC.e(TAG, "Still have a chance to lose the initializacion of list fragment >("); } /// Second fragment @@@ -306,12 -308,12 +305,12 @@@ } } else { - Log.wtf(TAG, "initFragments() called with invalid NULLs!"); + Log_OC.wtf(TAG, "initFragments() called with invalid NULLs!"); if (getAccount() == null) { - Log.wtf(TAG, "\t account is NULL"); + Log_OC.wtf(TAG, "\t account is NULL"); } if (getFile() == null) { - Log.wtf(TAG, "\t file is NULL"); + Log_OC.wtf(TAG, "\t file is NULL"); } } } @@@ -450,16 -452,6 +449,16 @@@ } @Override + public boolean onPrepareOptionsMenu(Menu menu) { + if (BuildConfig.DEBUG) { + menu.findItem(R.id.action_logger).setVisible(true); + } else { + menu.findItem(R.id.action_logger).setVisible(false); + } + return super.onPrepareOptionsMenu(menu); + } + + @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getSherlock().getMenuInflater(); inflater.inflate(R.menu.main_menu, menu); @@@ -489,11 -481,6 +488,11 @@@ startActivity(settingsIntent); break; } + case R.id.action_logger: { + Intent loggerIntent = new Intent(getApplicationContext(),LogHistoryActivity.class); + startActivity(loggerIntent); + break; + } case android.R.id.home: { FileFragment second = getSecondFragment(); OCFile currentDir = getCurrentDir(); @@@ -504,6 -491,38 +503,38 @@@ } break; } + case R.id.action_sort: { + SharedPreferences appPreferences = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + // Read sorting order, default to sort by name ascending + Integer sortOrder = appPreferences + .getInt("sortOrder", 0); + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.actionbar_sort_title) + .setSingleChoiceItems(R.array.actionbar_sortby, sortOrder , new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + + switch (which){ + case 0: + sortByName(true); + break; + case 1: + sortByDate(false); + break; + case 2: + sortBySize(false); + break; + } + + dialog.dismiss(); + + } + }); + builder.create().show(); + break; + } default: retval = super.onOptionsItemSelected(item); } @@@ -1039,7 -1058,7 +1070,7 @@@ } ocFileListFragment.setMessageForEmptyList(getString(message)); } else { - Log.e(TAG, "OCFileListFragment is null"); + Log_OC.e(TAG, "OCFileListFragment is null"); } } @@@ -1166,7 -1185,7 +1197,7 @@@ OCFile root = getStorageManager().getFileByPath(OCFile.ROOT_PATH); listOfFiles.listDirectory(root); setFile(listOfFiles.getCurrentFile()); - startSyncFolderOperation(root); + startSyncFolderOperation(root, false); } cleanSecondFragment(); } @@@ -1181,7 -1200,7 +1212,7 @@@ setNavigationListWithFolder(folder); listOfFiles.listDirectory(folder); setFile(listOfFiles.getCurrentFile()); - startSyncFolderOperation(folder); + startSyncFolderOperation(folder, false); } else { Log_OC.e(TAG, "Unexpected null when accessing list fragment"); } @@@ -1200,7 -1219,7 +1231,7 @@@ cleanSecondFragment(); // Sync Folder - startSyncFolderOperation(directory); + startSyncFolderOperation(directory, false); } @@@ -1317,7 -1336,7 +1348,7 @@@ @Override public void onSavedCertificate() { - startSyncFolderOperation(getCurrentDir()); + startSyncFolderOperation(getCurrentDir(), false); } @@@ -1605,7 -1624,7 +1636,7 @@@ return null; } - public void startSyncFolderOperation(OCFile folder) { + public void startSyncFolderOperation(OCFile folder, boolean ignoreETag) { long currentSyncTime = System.currentTimeMillis(); mSyncInProgress = true; @@@ -1615,7 -1634,6 +1646,7 @@@ currentSyncTime, false, getFileOperationsHelper().isSharedSupported(), + ignoreETag, getStorageManager(), getAccount(), getApplicationContext() @@@ -1728,24 -1746,28 +1759,36 @@@ } @Override + public void onRefresh(boolean ignoreETag) { + refreshList(ignoreETag); + } + + @Override public void onRefresh() { + refreshList(true); + } + + private void refreshList(boolean ignoreETag) { OCFileListFragment listOfFiles = getListOfFilesFragment(); if (listOfFiles != null) { OCFile folder = listOfFiles.getCurrentFile(); if (folder != null) { /*mFile = mContainerActivity.getStorageManager().getFileById(mFile.getFileId()); listDirectory(mFile);*/ - startSyncFolderOperation(folder); + startSyncFolderOperation(folder, ignoreETag); } } } - ++ + private void sortByDate(boolean ascending){ + getListOfFilesFragment().sortByDate(ascending); + } + + private void sortBySize(boolean ascending){ + getListOfFilesFragment().sortBySize(ascending); + } + + private void sortByName(boolean ascending){ + getListOfFilesFragment().sortByName(ascending); + } - } diff --combined src/com/owncloud/android/ui/adapter/FileListListAdapter.java index ffdad175,a90773ef..ffc2d69f --- a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java +++ b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java @@@ -18,20 -18,14 +18,24 @@@ package com.owncloud.android.ui.adapter; import java.io.File; +import java.lang.ref.WeakReference; + import java.util.Collections; + import java.util.Comparator; import java.util.Vector; import android.accounts.Account; import android.content.Context; + import android.content.SharedPreferences; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Bitmap.CompressFormat; +import android.graphics.BitmapFactory; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.media.ThumbnailUtils; +import android.os.AsyncTask; + import android.preference.PreferenceManager; +import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@@ -43,14 -37,15 +47,17 @@@ import android.widget.TextView import com.owncloud.android.R; import com.owncloud.android.authentication.AccountUtils; + import com.owncloud.android.datamodel.AlphanumComparator; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; +import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.ui.activity.ComponentsGetter; +import com.owncloud.android.utils.BitmapUtils; import com.owncloud.android.utils.DisplayUtils; + import com.owncloud.android.utils.FileStorageUtils; -import com.owncloud.android.utils.Log_OC; ++ /** @@@ -58,13 -53,10 +65,13 @@@ * instance. * * @author Bartek Przybylski - * + * @author Tobias Kaminsky + * @author David A. Velasco */ public class FileListListAdapter extends BaseAdapter implements ListAdapter { private final static String PERMISSION_SHARED_WITH_ME = "S"; + + private static final String TAG = FileListListAdapter.class.getSimpleName(); private Context mContext; private OCFile mFile = null; @@@ -74,160 -66,28 +81,172 @@@ private FileDataStorageManager mStorageManager; private Account mAccount; private ComponentsGetter mTransferServiceGetter; + private Integer sortOrder; + private Boolean sortAscending; + private SharedPreferences appPreferences; + private final Object thumbnailDiskCacheLock = new Object(); + private DiskLruImageCache mThumbnailCache; + private boolean mThumbnailCacheStarting = true; + private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB + private static final CompressFormat mCompressFormat = CompressFormat.JPEG; + private static final int mCompressQuality = 70; + private Bitmap defaultImg; + public FileListListAdapter( boolean justFolders, Context context, ComponentsGetter transferServiceGetter ) { + mJustFolders = justFolders; mContext = context; mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext); mTransferServiceGetter = transferServiceGetter; + + appPreferences = PreferenceManager + .getDefaultSharedPreferences(mContext); + + // Read sorting order, default to sort by name ascending + sortOrder = appPreferences + .getInt("sortOrder", 0); + sortAscending = appPreferences.getBoolean("sortAscending", true); + + defaultImg = BitmapFactory.decodeResource(mContext.getResources(), + DisplayUtils.getResourceId("image/png", "default.png")); + + // Initialise disk cache on background thread + new InitDiskCacheTask().execute(); + } + + class InitDiskCacheTask extends AsyncTask { + @Override + protected Void doInBackground(File... params) { + synchronized (thumbnailDiskCacheLock) { + try { + mThumbnailCache = new DiskLruImageCache(mContext, "thumbnailCache", + DISK_CACHE_SIZE, mCompressFormat, mCompressQuality); + } catch (Exception e) { + Log_OC.d(TAG, "Thumbnail cache could not be opened ", e); + mThumbnailCache = null; + } + mThumbnailCacheStarting = false; // Finished initialization + thumbnailDiskCacheLock.notifyAll(); // Wake any waiting threads + } + return null; + } + } + + static class AsyncDrawable extends BitmapDrawable { + private final WeakReference bitmapWorkerTaskReference; + + public AsyncDrawable(Resources res, Bitmap bitmap, + ThumbnailGenerationTask bitmapWorkerTask) { + super(res, bitmap); + bitmapWorkerTaskReference = + new WeakReference(bitmapWorkerTask); + } + + public ThumbnailGenerationTask getBitmapWorkerTask() { + return bitmapWorkerTaskReference.get(); + } + } + + class ThumbnailGenerationTask extends AsyncTask { + private final WeakReference imageViewReference; + private OCFile file; + + + public ThumbnailGenerationTask(ImageView imageView) { + // Use a WeakReference to ensure the ImageView can be garbage collected + imageViewReference = new WeakReference(imageView); + } + + // Decode image in background. + @Override + protected Bitmap doInBackground(OCFile... params) { + Bitmap thumbnail = null; + + try { + file = params[0]; + final String imageKey = String.valueOf(file.getRemoteId()); + + // Check disk cache in background thread + thumbnail = getBitmapFromDiskCache(imageKey); + + // Not found in disk cache + if (thumbnail == null || file.needsUpdateThumbnail()) { + // Converts dp to pixel + Resources r = mContext.getResources(); + int px = (int) Math.round(TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, 150, r.getDisplayMetrics() + )); + + if (file.isDown()){ + Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile( + file.getStoragePath(), px, px); + + if (bitmap != null) { + thumbnail = ThumbnailUtils.extractThumbnail(bitmap, px, px); + + // Add thumbnail to cache + addBitmapToCache(imageKey, thumbnail); + + file.setNeedsUpdateThumbnail(false); + mStorageManager.saveFile(file); + } + + } + } + + } catch (Throwable t) { + // the app should never break due to a problem with thumbnails + Log_OC.e(TAG, "Generation of thumbnail for " + file + " failed", t); + if (t instanceof OutOfMemoryError) { + System.gc(); + } + } + + return thumbnail; + } + + protected void onPostExecute(Bitmap bitmap){ + if (isCancelled()) { + bitmap = null; + } + + if (imageViewReference != null && bitmap != null) { + final ImageView imageView = imageViewReference.get(); + final ThumbnailGenerationTask bitmapWorkerTask = + getBitmapWorkerTask(imageView); + if (this == bitmapWorkerTask && imageView != null) { + imageView.setImageBitmap(bitmap); + } + } + } + } + + public void addBitmapToCache(String key, Bitmap bitmap) { + synchronized (thumbnailDiskCacheLock) { + if (mThumbnailCache != null) { + mThumbnailCache.put(key, bitmap); + } + } + } + + public Bitmap getBitmapFromDiskCache(String key) { + synchronized (thumbnailDiskCacheLock) { + // Wait while disk cache is started from background thread + while (mThumbnailCacheStarting) { + try { + thumbnailDiskCacheLock.wait(); + } catch (InterruptedException e) {} + } + if (mThumbnailCache != null) { + return (Bitmap) mThumbnailCache.getBitmap(key); + } + } - return null; ++ return null; } @Override @@@ -272,10 -132,10 +291,10 @@@ .getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflator.inflate(R.layout.list_item, null); } - + if (mFiles != null && mFiles.size() > position) { OCFile file = mFiles.get(position); - TextView fileName = (TextView) view.findViewById(R.id.Filename); + TextView fileName = (TextView) view.findViewById(R.id.Filename); String name = file.getFileName(); fileName.setText(name); @@@ -286,8 -146,7 +305,8 @@@ ImageView localStateView = (ImageView) view.findViewById(R.id.imageView2); localStateView.bringToFront(); - FileDownloaderBinder downloaderBinder = mTransferServiceGetter.getFileDownloaderBinder(); + FileDownloaderBinder downloaderBinder = + mTransferServiceGetter.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = mTransferServiceGetter.getFileUploaderBinder(); if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file)) { localStateView.setImageResource(R.drawable.downloading_file_indicator); @@@ -310,9 -169,7 +329,9 @@@ fileSizeV.setVisibility(View.VISIBLE); fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength())); lastModV.setVisibility(View.VISIBLE); - lastModV.setText(DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp())); + lastModV.setText( + DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp()) + ); // this if-else is needed even thoe fav icon is visible by default // because android reuses views in listview if (!file.keepInSync()) { @@@ -331,42 -188,24 +350,47 @@@ checkBoxV.setImageResource(android.R.drawable.checkbox_off_background); } checkBoxV.setVisibility(View.VISIBLE); + } + + // get Thumbnail if file is image + if (file.isImage()){ + // Thumbnail in Cache? + Bitmap thumbnail = getBitmapFromDiskCache(String.valueOf(file.getRemoteId())); + if (thumbnail != null && !file.needsUpdateThumbnail()){ + fileIcon.setImageBitmap(thumbnail); + } else { + // generate new Thumbnail + if (cancelPotentialWork(file, fileIcon)) { + final ThumbnailGenerationTask task = + new ThumbnailGenerationTask(fileIcon); + final AsyncDrawable asyncDrawable = + new AsyncDrawable(mContext.getResources(), defaultImg, task); + fileIcon.setImageDrawable(asyncDrawable); + task.execute(file); + } + } + } else { + fileIcon.setImageResource( + DisplayUtils.getResourceId(file.getMimetype(), file.getFileName()) + ); } - - fileIcon.setImageResource(DisplayUtils.getResourceId(file.getMimetype(), file.getFileName())); - + if (checkIfFileIsSharedWithMe(file)) { sharedWithMeIconV.setVisibility(View.VISIBLE); } } else { - fileSizeV.setVisibility(View.INVISIBLE); - //fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength())); + if (FileStorageUtils.getDefaultSavePathFor(mAccount.name, file) != null){ + fileSizeV.setVisibility(View.VISIBLE); + fileSizeV.setText(getFolderSizeHuman(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file))); + } else { + fileSizeV.setVisibility(View.INVISIBLE); + } - ++ lastModV.setVisibility(View.VISIBLE); - lastModV.setText(DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp())); + lastModV.setText( + DisplayUtils.unixTimeToHumanReadable(file.getModificationTimestamp()) + ); checkBoxV.setVisibility(View.GONE); view.findViewById(R.id.imageView3).setVisibility(View.GONE); @@@ -374,9 -213,7 +398,9 @@@ fileIcon.setImageResource(R.drawable.shared_with_me_folder); sharedWithMeIconV.setVisibility(View.VISIBLE); } else { - fileIcon.setImageResource(DisplayUtils.getResourceId(file.getMimetype(), file.getFileName())); + fileIcon.setImageResource( + DisplayUtils.getResourceId(file.getMimetype(), file.getFileName()) + ); } // If folder is sharedByLink, icon folder must be changed to @@@ -395,35 -232,48 +419,77 @@@ return view; } - ++ + public static boolean cancelPotentialWork(OCFile file, ImageView imageView) { + final ThumbnailGenerationTask bitmapWorkerTask = getBitmapWorkerTask(imageView); + + if (bitmapWorkerTask != null) { + final OCFile bitmapData = bitmapWorkerTask.file; + // If bitmapData is not yet set or it differs from the new data + if (bitmapData == null || bitmapData != file) { + // Cancel previous task + bitmapWorkerTask.cancel(true); + } else { + // The same work is already in progress + return false; + } + } + // No task associated with the ImageView, or an existing task was cancelled + return true; + } + private static ThumbnailGenerationTask getBitmapWorkerTask(ImageView imageView) { + if (imageView != null) { + final Drawable drawable = imageView.getDrawable(); + if (drawable instanceof AsyncDrawable) { + final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; + return asyncDrawable.getBitmapWorkerTask(); + } + } + return null; + } ++ + /** + * Local Folder size in human readable format + * @param path String + * @return Size in human readable format + */ + private String getFolderSizeHuman(String path) { + + File dir = new File(path); + + if(dir.exists()) { + long bytes = getFolderSize(dir); + if (bytes < 1024) return bytes + " B"; + int exp = (int) (Math.log(bytes) / Math.log(1024)); + String pre = ("KMGTPE").charAt(exp-1) + ""; + + return String.format("%.1f %sB", bytes / Math.pow(1024, exp), pre); + } + + return "0 B"; + } + + /** + * Local Folder size + * @param dir File + * @return Size in bytes + */ + private long getFolderSize(File dir) { + if (dir.exists()) { + long result = 0; + File[] fileList = dir.listFiles(); + for(int i = 0; i < fileList.length; i++) { + if(fileList[i].isDirectory()) { + result += getFolderSize(fileList[i]); + } else { + result += fileList[i].length(); + } + } + return result; + } + return 0; - } ++ } @Override public int getViewTypeCount() { @@@ -442,10 -292,8 +508,10 @@@ /** * Change the adapted directory for a new one - * @param directory New file to adapt. Can be NULL, meaning "no content to adapt". - * @param updatedStorageManager Optional updated storage manager; used to replace mStorageManager if is different (and not NULL) + * @param directory New file to adapt. Can be NULL, meaning + * "no content to adapt". + * @param updatedStorageManager Optional updated storage manager; used to replace + * mStorageManager if is different (and not NULL) */ public void swapDirectory(OCFile directory, FileDataStorageManager updatedStorageManager) { mFile = directory; @@@ -461,6 -309,26 +527,26 @@@ } else { mFiles = null; } + + sortDirectory(); + } + + /** + * Sorts all filenames, regarding last user decision + */ + private void sortDirectory(){ + switch (sortOrder){ + case 0: + sortByName(sortAscending); + break; + case 1: + sortByDate(sortAscending); + break; + case 2: + sortBySize(sortAscending); + break; + } + notifyDataSetChanged(); } @@@ -491,9 -359,106 +577,108 @@@ * @return boolean: True if it is shared with me and false if it is not */ private boolean checkIfFileIsSharedWithMe(OCFile file) { - return (mFile.getPermissions() != null && !mFile.getPermissions().contains(PERMISSION_SHARED_WITH_ME) - && file.getPermissions() != null && file.getPermissions().contains(PERMISSION_SHARED_WITH_ME)); + return (mFile.getPermissions() != null + && !mFile.getPermissions().contains(PERMISSION_SHARED_WITH_ME) + && file.getPermissions() != null + && file.getPermissions().contains(PERMISSION_SHARED_WITH_ME)); } + + /** + * Sorts list by Date + * @param sortAscending true: ascending, false: descending + */ + private void sortByDate(boolean sortAscending){ + final Integer val; + if (sortAscending){ + val = 1; + } else { + val = -1; + } + + Collections.sort(mFiles, new Comparator() { + public int compare(OCFile o1, OCFile o2) { + if (o1.isFolder() && o2.isFolder()) { + return val * Long.compare(o1.getModificationTimestamp(), o2.getModificationTimestamp()); + } + else if (o1.isFolder()) { + return -1; + } else if (o2.isFolder()) { + return 1; + } else if (o1.getModificationTimestamp() == 0 || o2.getModificationTimestamp() == 0){ + return 0; + } else { + return val * Long.compare(o1.getModificationTimestamp(), o2.getModificationTimestamp()); + } + } + }); + } + + /** + * Sorts list by Size + * @param sortAscending true: ascending, false: descending + */ + private void sortBySize(boolean sortAscending){ + final Integer val; + if (sortAscending){ + val = 1; + } else { + val = -1; + } + + Collections.sort(mFiles, new Comparator() { + public int compare(OCFile o1, OCFile o2) { + if (o1.isFolder() && o2.isFolder()) { + return val * Long.compare(getFolderSize(new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, o1))), + getFolderSize(new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, o2)))); + } + else if (o1.isFolder()) { + return -1; + } else if (o2.isFolder()) { + return 1; + } else if (o1.getFileLength() == 0 || o2.getFileLength() == 0){ + return 0; + } else { + return val * Long.compare(o1.getFileLength(), o2.getFileLength()); + } + } + }); + } + + /** + * Sorts list by Name + * @param sortAscending true: ascending, false: descending + */ + private void sortByName(boolean sortAscending){ + final Integer val; + if (sortAscending){ + val = 1; + } else { + val = -1; + } + + Collections.sort(mFiles, new Comparator() { + public int compare(OCFile o1, OCFile o2) { + if (o1.isFolder() && o2.isFolder()) { + return val * o1.getRemotePath().toLowerCase().compareTo(o2.getRemotePath().toLowerCase()); + } else if (o1.isFolder()) { + return -1; + } else if (o2.isFolder()) { + return 1; + } + return val * new AlphanumComparator().compare(o1, o2); + } + }); + } + + public void setSortOrder(Integer order, boolean ascending) { + SharedPreferences.Editor editor = appPreferences.edit(); + editor.putInt("sortOrder", order); + editor.putBoolean("sortAscending", ascending); + editor.commit(); + + sortOrder = order; + sortAscending = ascending; + + sortDirectory(); + } } diff --combined src/com/owncloud/android/ui/fragment/OCFileListFragment.java index 3665fe0b,7cac16e7..aff51d3a --- a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java @@@ -34,16 -34,15 +34,16 @@@ import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.FileMenuFilter; +import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.ui.activity.MoveActivity; +import com.owncloud.android.ui.activity.OnEnforceableRefreshListener; import com.owncloud.android.ui.adapter.FileListListAdapter; import com.owncloud.android.ui.dialog.ConfirmationDialogFragment; import com.owncloud.android.ui.dialog.RemoveFileDialogFragment; import com.owncloud.android.ui.dialog.RenameFileDialogFragment; import com.owncloud.android.ui.preview.PreviewImageFragment; import com.owncloud.android.ui.preview.PreviewMediaFragment; -import com.owncloud.android.utils.Log_OC; /** * A Fragment that lists all files and folders in a given path. @@@ -89,7 -88,7 +89,7 @@@ public class OCFileListFragment extend FileFragment.ContainerActivity.class.getSimpleName()); } try { - setOnRefreshListener((SwipeRefreshLayout.OnRefreshListener) activity); + setOnRefreshListener((OnEnforceableRefreshListener) activity); } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement " + @@@ -175,7 -174,7 +175,7 @@@ listDirectory(mFile); - onRefresh(); + onRefresh(false); // restore index and top position restoreIndexAndTopPosition(); @@@ -386,5 -385,16 +386,16 @@@ mFile = directory; } } + + public void sortByName(boolean descending){ + mAdapter.setSortOrder(0, descending); + } + + public void sortByDate(boolean descending){ + mAdapter.setSortOrder(1, descending); + } + public void sortBySize(boolean descending){ + mAdapter.setSortOrder(2, descending); + } }