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=95639df3ae0ed89cb70497bf0b3607d57f8e9aad 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 --- diff --git a/res/menu/main_menu.xml b/res/menu/main_menu.xml index 1df273ea..6e64fcf7 100644 --- a/res/menu/main_menu.xml +++ b/res/menu/main_menu.xml @@ -49,6 +49,11 @@ android:orderInCategory="2" android:showAsAction="never" android:title="@string/actionbar_logger"/> + diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 0b536c10..e8f43195 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -11,6 +11,13 @@ Einstellungen Details Senden + Sortieren + Sortieren nach + + A-Z + Neu - Alt + Groß - Klein + Allgemein Mehr Konten diff --git a/res/values/strings.xml b/res/values/strings.xml index 4c7cf34d..4c5f57b0 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -12,6 +12,13 @@ Settings Details Send + Sort + Sort by + + A-Z + Newest - Oldest + Biggest - Smallest + General More Accounts diff --git a/src/com/owncloud/android/datamodel/AlphanumComparator.java b/src/com/owncloud/android/datamodel/AlphanumComparator.java new file mode 100644 index 00000000..f78ef25a --- /dev/null +++ b/src/com/owncloud/android/datamodel/AlphanumComparator.java @@ -0,0 +1,127 @@ +/* + * The Alphanum Algorithm is an improved sorting algorithm for strings + * containing numbers. Instead of sorting numbers in ASCII order like + * a standard sort, this algorithm sorts numbers in numeric order. + * + * The Alphanum Algorithm is discussed at http://www.DaveKoelle.com + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +package com.owncloud.android.datamodel; +import java.util.Comparator; + +/** + * This is an updated version with enhancements made by Daniel Migowski, + * Andre Bogus, and David Koelle + * + * To convert to use Templates (Java 1.5+): + * - Change "implements Comparator" to "implements Comparator" + * - Change "compare(Object o1, Object o2)" to "compare(String s1, String s2)" + * - Remove the type checking and casting in compare(). + * + * To use this class: + * Use the static "sort" method from the java.util.Collections class: + * Collections.sort(your list, new AlphanumComparator()); + */ +public class AlphanumComparator implements Comparator +{ + private final boolean isDigit(char ch) + { + return ch >= 48 && ch <= 57; + } + + /** Length of string is passed in for improved efficiency (only need to calculate it once) **/ + private final String getChunk(String s, int slength, int marker) + { + StringBuilder chunk = new StringBuilder(); + char c = s.charAt(marker); + chunk.append(c); + marker++; + if (isDigit(c)) + { + while (marker < slength) + { + c = s.charAt(marker); + if (!isDigit(c)) + break; + chunk.append(c); + marker++; + } + } else + { + while (marker < slength) + { + c = s.charAt(marker); + if (isDigit(c)) + break; + chunk.append(c); + marker++; + } + } + return chunk.toString(); + } + + public int compare(OCFile o1, OCFile o2) + { + String s1 = (String)o1.getRemotePath().toLowerCase(); + String s2 = (String)o2.getRemotePath().toLowerCase(); + + int thisMarker = 0; + int thatMarker = 0; + int s1Length = s1.length(); + int s2Length = s2.length(); + + while (thisMarker < s1Length && thatMarker < s2Length) + { + String thisChunk = getChunk(s1, s1Length, thisMarker); + thisMarker += thisChunk.length(); + + String thatChunk = getChunk(s2, s2Length, thatMarker); + thatMarker += thatChunk.length(); + + // If both chunks contain numeric characters, sort them numerically + int result = 0; + if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0))) + { + // Simple chunk comparison by length. + int thisChunkLength = thisChunk.length(); + result = thisChunkLength - thatChunk.length(); + // If equal, the first different number counts + if (result == 0) + { + for (int i = 0; i < thisChunkLength; i++) + { + result = thisChunk.charAt(i) - thatChunk.charAt(i); + if (result != 0) + { + return result; + } + } + } + } else + { + result = thisChunk.compareTo(thatChunk); + } + + if (result != 0) + return result; + } + + return s1Length - s2Length; + } +} diff --git a/src/com/owncloud/android/datamodel/OCFile.java b/src/com/owncloud/android/datamodel/OCFile.java index c3284fc0..7ef9bc55 100644 --- a/src/com/owncloud/android/datamodel/OCFile.java +++ b/src/com/owncloud/android/datamodel/OCFile.java @@ -460,7 +460,7 @@ public class OCFile implements Parcelable, Comparable { } else if (another.isFolder()) { return 1; } - return getRemotePath().toLowerCase().compareTo(another.getRemotePath().toLowerCase()); + return new AlphanumComparator().compare(this, another); } @Override diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index 21472fd1..8560ddbb 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -48,7 +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.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; @@ -151,7 +150,7 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { private String DIALOG_UNTRUSTED_CERT; private OCFile mWaitingToSend; - + @Override protected void onCreate(Bundle savedInstanceState) { Log_OC.d(TAG, "onCreate() start"); @@ -504,6 +503,38 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { } 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); } @@ -1748,4 +1779,16 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener { } } } + + 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 --git a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java index ffdad175..ffc2d69f 100644 --- a/src/com/owncloud/android/ui/adapter/FileListListAdapter.java +++ b/src/com/owncloud/android/ui/adapter/FileListListAdapter.java @@ -19,10 +19,13 @@ 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; @@ -31,6 +34,7 @@ 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; @@ -43,6 +47,7 @@ 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; @@ -51,6 +56,8 @@ 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; + /** @@ -74,6 +81,9 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter { 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; @@ -93,6 +103,15 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter { 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")); @@ -227,7 +246,7 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter { return (Bitmap) mThumbnailCache.getBitmap(key); } } - return null; + return null; } @Override @@ -361,8 +380,13 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter { } } 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()) @@ -395,7 +419,7 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter { return view; } - + public static boolean cancelPotentialWork(OCFile file, ImageView imageView) { final ThumbnailGenerationTask bitmapWorkerTask = getBitmapWorkerTask(imageView); @@ -424,6 +448,48 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter { } 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() { @@ -461,6 +527,26 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter { } 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(); } @@ -496,4 +582,103 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter { && 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 --git a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java index 3665fe0b..aff51d3a 100644 --- a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -386,5 +386,16 @@ public class OCFileListFragment extends ExtendedListFragment { 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); + } }