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
This commit is contained in:
jabarros 2014-10-09 17:26:02 +02:00
commit 7d9fc6857e
8 changed files with 392 additions and 7 deletions

View file

@ -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> -->

View file

@ -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>

View file

@ -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>

View file

@ -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;
}
}

View file

@ -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

View file

@ -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;
@ -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);
}
}

View file

@ -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"));
@ -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())
@ -425,6 +449,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() {
return 1;
@ -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();
}
}

View file

@ -387,4 +387,15 @@ public class OCFileListFragment extends ExtendedListFragment {
}
}
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);
}
}