Fixed an issue caused by symlinks not handled correctly.

This commit is contained in:
Karim Abou Zeid 2016-03-19 13:57:43 +01:00
commit e5ad02e8a9
6 changed files with 58 additions and 37 deletions

View file

@ -21,13 +21,14 @@ import com.kabouzeid.gramophone.adapter.base.MediaEntryViewHolder;
import com.kabouzeid.gramophone.glide.audiocover.AudioFileCover; import com.kabouzeid.gramophone.glide.audiocover.AudioFileCover;
import com.kabouzeid.gramophone.interfaces.CabHolder; import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.util.Util; import com.kabouzeid.gramophone.util.Util;
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
import java.io.File; import java.io.File;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class SongFileAdapter extends AbsMultiSelectAdapter<SongFileAdapter.ViewHolder, File> { public class SongFileAdapter extends AbsMultiSelectAdapter<SongFileAdapter.ViewHolder, File> implements FastScrollRecyclerView.SectionedAdapter {
private static final int FILE = 0; private static final int FILE = 0;
private static final int FOLDER = 1; private static final int FOLDER = 1;
@ -114,7 +115,7 @@ public class SongFileAdapter extends AbsMultiSelectAdapter<SongFileAdapter.ViewH
holder.image.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); holder.image.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN);
holder.image.setImageResource(R.drawable.ic_folder_white_24dp); holder.image.setImageResource(R.drawable.ic_folder_white_24dp);
} else { } else {
Drawable error = Util.getTintedDrawable(activity, R.drawable.ic_music_note_white_24dp, iconColor); Drawable error = Util.getTintedDrawable(activity, R.drawable.ic_file_music_white_24dp, iconColor);
Glide.with(activity) Glide.with(activity)
.load(new AudioFileCover(file.getPath())) .load(new AudioFileCover(file.getPath()))
.diskCacheStrategy(DiskCacheStrategy.NONE) .diskCacheStrategy(DiskCacheStrategy.NONE)
@ -164,6 +165,12 @@ public class SongFileAdapter extends AbsMultiSelectAdapter<SongFileAdapter.ViewH
} }
} }
@NonNull
@Override
public String getSectionName(int position) {
return String.valueOf(dataSet.get(position).getName().charAt(0)).toUpperCase();
}
public class ViewHolder extends MediaEntryViewHolder { public class ViewHolder extends MediaEntryViewHolder {
public ViewHolder(View itemView) { public ViewHolder(View itemView) {

View file

@ -42,6 +42,7 @@ import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
import java.io.File; import java.io.File;
import java.io.FileFilter; import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -51,7 +52,6 @@ import java.util.List;
import butterknife.Bind; import butterknife.Bind;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import hugo.weaving.DebugLog;
public class FolderFragment extends AbsMainActivityFragment implements MainActivity.MainActivityFragmentCallbacks, CabHolder, BreadCrumbLayout.SelectionCallback, SongFileAdapter.Callbacks, AppBarLayout.OnOffsetChangedListener { public class FolderFragment extends AbsMainActivityFragment implements MainActivity.MainActivityFragmentCallbacks, CabHolder, BreadCrumbLayout.SelectionCallback, SongFileAdapter.Callbacks, AppBarLayout.OnOffsetChangedListener {
public static final String TAG = FolderFragment.class.getSimpleName(); public static final String TAG = FolderFragment.class.getSimpleName();
@ -90,7 +90,6 @@ public class FolderFragment extends AbsMainActivityFragment implements MainActiv
return frag; return frag;
} }
@DebugLog
public void setCrumb(BreadCrumbLayout.Crumb crumb, boolean addToHistory) { public void setCrumb(BreadCrumbLayout.Crumb crumb, boolean addToHistory) {
saveScrollPosition(); saveScrollPosition();
updateAdapter(crumb.getFile()); updateAdapter(crumb.getFile());
@ -153,7 +152,7 @@ public class FolderFragment extends AbsMainActivityFragment implements MainActiv
setUpRecyclerView(); setUpRecyclerView();
if (savedInstanceState == null) { if (savedInstanceState == null) {
setCrumb(new BreadCrumbLayout.Crumb((File) getArguments().getSerializable(PATH)), true); setCrumb(new BreadCrumbLayout.Crumb(tryGetCanonicalFile((File) getArguments().getSerializable(PATH))), true);
} else { } else {
breadCrumbs.restoreFromStateWrapper((BreadCrumbLayout.SavedStateWrapper) savedInstanceState.getParcelable(CRUMBS)); breadCrumbs.restoreFromStateWrapper((BreadCrumbLayout.SavedStateWrapper) savedInstanceState.getParcelable(CRUMBS));
setCrumb(breadCrumbs.getCrumb(breadCrumbs.getActiveIndex()), true); setCrumb(breadCrumbs.getCrumb(breadCrumbs.getActiveIndex()), true);
@ -234,8 +233,8 @@ public class FolderFragment extends AbsMainActivityFragment implements MainActiv
@Override @Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) { public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.action_go_to_standard_folder: case R.id.action_go_to_music_folder:
setCrumb(new BreadCrumbLayout.Crumb(getDefaultStartFolder()), true); setCrumb(new BreadCrumbLayout.Crumb(tryGetCanonicalFile(getDefaultStartFolder())), true);
return true; return true;
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
@ -262,6 +261,7 @@ public class FolderFragment extends AbsMainActivityFragment implements MainActiv
@Override @Override
public void onFileSelected(File file) { public void onFileSelected(File file) {
file = tryGetCanonicalFile(file); // important as we compare the path value later
if (file.isDirectory()) { if (file.isDirectory()) {
setCrumb(new BreadCrumbLayout.Crumb(file), true); setCrumb(new BreadCrumbLayout.Crumb(file), true);
} else { } else {
@ -274,7 +274,7 @@ public class FolderFragment extends AbsMainActivityFragment implements MainActiv
int startIndex = -1; int startIndex = -1;
for (int i = 0; i < songs.size(); i++) { for (int i = 0; i < songs.size(); i++) {
if (file.getPath().equals(songs.get(i).data)) { if (file.getPath().equals(songs.get(i).data)) { // path is already canonical here
startIndex = i; startIndex = i;
break; break;
} }
@ -295,8 +295,13 @@ public class FolderFragment extends AbsMainActivityFragment implements MainActiv
if (files != null) { if (files != null) {
paths = new String[files.size()]; paths = new String[files.size()];
for (int i = 0; i < files.size(); i++) { for (int i = 0; i < files.size(); i++) {
try {
paths[i] = files.get(i).getCanonicalPath(); // canonical path is important here because we want to compare the path with the media store entry later
} catch (IOException e) {
e.printStackTrace();
paths[i] = files.get(i).getPath(); paths[i] = files.get(i).getPath();
} }
}
if (files.size() > 0 && files.size() < 999) { // 999 is the max amount Androids SQL implementation can handle. if (files.size() > 0 && files.size() < 999) { // 999 is the max amount Androids SQL implementation can handle.
selection = AudioColumns.DATA + " IN (" + makePlaceholders(files.size()) + ")"; selection = AudioColumns.DATA + " IN (" + makePlaceholders(files.size()) + ")";
@ -402,15 +407,28 @@ public class FolderFragment extends AbsMainActivityFragment implements MainActiv
} }
} }
Comparator<File> fileComparator = new Comparator<File>() {
@Override
public int compare(File lhs, File rhs) {
if (lhs.isDirectory() && !rhs.isDirectory()) {
return -1;
} else if (!lhs.isDirectory() && rhs.isDirectory()) {
return 1;
} else {
return lhs.getName().compareToIgnoreCase(rhs.getName());
}
}
};
private List<File> sort(List<File> files) { private List<File> sort(List<File> files) {
Collections.sort(files, new FileSorter()); Collections.sort(files, fileComparator);
return files; return files;
} }
FileFilter audioFileFilter = new FileFilter() { FileFilter audioFileFilter = new FileFilter() {
@Override @Override
public boolean accept(File pathname) { public boolean accept(File file) {
return pathname.isDirectory() || fileIsMimeType(pathname, "audio/*", MimeTypeMap.getSingleton()); return !file.isHidden() && (file.isDirectory() || fileIsMimeType(file, "audio/*", MimeTypeMap.getSingleton()));
} }
}; };
@ -418,7 +436,7 @@ public class FolderFragment extends AbsMainActivityFragment implements MainActiv
return audioFileFilter; return audioFileFilter;
} }
static boolean fileIsMimeType(File file, String mimeType, MimeTypeMap mimeTypeMap) { private static boolean fileIsMimeType(File file, String mimeType, MimeTypeMap mimeTypeMap) {
if (mimeType == null || mimeType.equals("*/*")) { if (mimeType == null || mimeType.equals("*/*")) {
return true; return true;
} else { } else {
@ -459,16 +477,12 @@ public class FolderFragment extends AbsMainActivityFragment implements MainActiv
return false; return false;
} }
private static class FileSorter implements Comparator<File> { private static File tryGetCanonicalFile(File file) {
@Override try {
public int compare(File lhs, File rhs) { return file.getCanonicalFile();
if (lhs.isDirectory() && !rhs.isDirectory()) { } catch (IOException e) {
return -1; e.printStackTrace();
} else if (!lhs.isDirectory() && rhs.isDirectory()) { return file;
return 1;
} else {
return lhs.getName().compareToIgnoreCase(rhs.getName());
}
} }
} }
} }

View file

@ -0,0 +1,10 @@
<!-- drawable/ic_file_music_white_24dpsic_white_24dp.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M9,16A2,2 0 0,0 7,18A2,2 0 0,0 9,20A2,2 0 0,0 11,18V13H14V11H10V16.27C9.71,16.1 9.36,16 9,16Z" />
</vector>

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0"
android:width="24dp">
<path
android:fillColor="#FFFFFF"
android:pathData="M20,6h-8l-2,-2L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,8c0,-1.1 -0.9,-2 -2,-2zM17.94,17L15,15.28 12.06,17l0.78,-3.33 -2.59,-2.24 3.41,-0.29L15,8l1.34,3.14 3.41,0.29 -2.59,2.24 0.78,3.33z" />
</vector>

View file

@ -3,9 +3,9 @@
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<item <item
android:id="@+id/action_go_to_standard_folder" android:id="@+id/action_go_to_music_folder"
android:icon="@drawable/ic_folder_special_white_24dp" android:icon="@drawable/ic_music_note_white_24dp"
android:title="@string/action_go_to_standard_folder" android:title="@string/action_go_to_music_folder"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
</menu> </menu>

View file

@ -96,7 +96,7 @@
<string name="action_shuffle_artist">Shuffle artist</string> <string name="action_shuffle_artist">Shuffle artist</string>
<string name="action_shuffle_playlist">Shuffle playlist</string> <string name="action_shuffle_playlist">Shuffle playlist</string>
<string name="action_clear_playing_queue">Clear playing queue</string> <string name="action_clear_playing_queue">Clear playing queue</string>
<string name="action_go_to_standard_folder">Go to standard folder</string> <string name="action_go_to_music_folder">Go to music folder</string>
<string name="last_opened">Last opened</string> <string name="last_opened">Last opened</string>
<string name="light_theme_name">Light</string> <string name="light_theme_name">Light</string>
<string name="dark_theme_name">Dark</string> <string name="dark_theme_name">Dark</string>