Эх сурвалжийг харах

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
jabarros 10 жил өмнө
parent
commit
7d9fc6857e

+ 5 - 0
res/menu/main_menu.xml

@@ -49,6 +49,11 @@
         android:orderInCategory="2"
         android:showAsAction="never"
         android:title="@string/actionbar_logger"/>
+	<item
+        android:id="@+id/action_sort"
+        android:orderInCategory="2"
+        android:showAsAction="never"
+        android:title="@string/actionbar_sort"/>
 
     <!-- <item android:id="@+id/search" android:title="@string/actionbar_search" android:icon="@drawable/ic_action_search"></item> -->
 

+ 7 - 0
res/values-de/strings.xml

@@ -11,6 +11,13 @@
   <string name="actionbar_settings">Einstellungen</string>
   <string name="actionbar_see_details">Details</string>
   <string name="actionbar_send_file">Senden</string>
+  <string name="actionbar_sort">Sortieren</string>
+  <string name="actionbar_sort_title">Sortieren nach</string>
+  <string-array name="actionbar_sortby">
+  	<item>A-Z</item>
+    	<item>Neu - Alt</item>
+    	<item>Groß - Klein</item>
+  </string-array>
   <string name="prefs_category_general">Allgemein</string>
   <string name="prefs_category_more">Mehr</string>
   <string name="prefs_accounts">Konten</string>

+ 7 - 0
res/values/strings.xml

@@ -12,6 +12,13 @@
     <string name="actionbar_settings">Settings</string>
     <string name="actionbar_see_details">Details</string>
     <string name="actionbar_send_file">Send</string>
+    <string name="actionbar_sort">Sort</string>
+    <string name="actionbar_sort_title">Sort by</string>
+    <string-array name="actionbar_sortby">
+    	<item>A-Z</item>
+    	<item>Newest - Oldest</item>
+    	<item>Biggest - Smallest</item>
+    </string-array>
     <string name="prefs_category_general">General</string>
     <string name="prefs_category_more">More</string>
     <string name="prefs_accounts">Accounts</string>

+ 127 - 0
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<String>"
+ *   - 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<OCFile>
+{
+    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;
+    }
+}

+ 1 - 1
src/com/owncloud/android/datamodel/OCFile.java

@@ -460,7 +460,7 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
         } else if (another.isFolder()) {
             return 1;
         }
-        return getRemotePath().toLowerCase().compareTo(another.getRemotePath().toLowerCase());
+        return new AlphanumComparator().compare(this, another);
     }
 
     @Override

+ 45 - 2
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);
+    }
 }

+ 189 - 4
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<OCFile>() {
+            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<OCFile>() {
+            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<OCFile>() {
+            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();
+    }    
 }

+ 11 - 0
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);
+    }    
 }