Add years to album header, determine album name based on entries in album header, make thread collection in ImageLoader concurrent

This commit is contained in:
Joshua Bahnsen 2014-01-26 16:47:13 -07:00
parent 4389698d7f
commit 36167e5ab9
9 changed files with 83 additions and 31 deletions

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:a="http://schemas.android.com/apk/res/android"
a:layout_width="fill_parent"
a:layout_height="wrap_content" >
a:layout_width="fill_parent"
a:layout_height="wrap_content">
<ImageView
a:id="@+id/select_album_art"
@ -12,7 +12,7 @@
a:layout_marginRight="10dip"
a:contentDescription="@null"
a:scaleType="fitCenter"
a:src="@drawable/unknown_album_large" />
a:src="@drawable/unknown_album_large"/>
<TextView
a:id="@+id/select_album_title"
@ -23,7 +23,7 @@
a:paddingRight="4dip"
a:paddingTop="10dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceMedium" />
a:textAppearance="?android:attr/textAppearanceMedium"/>
<TextView
a:id="@+id/select_album_artist"
@ -34,7 +34,7 @@
a:ellipsize="end"
a:paddingRight="4dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceSmall" />
a:textAppearance="?android:attr/textAppearanceSmall"/>
<TextView
a:id="@+id/select_album_genre"
@ -45,18 +45,29 @@
a:ellipsize="end"
a:paddingRight="4dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceSmall" />
a:textAppearance="?android:attr/textAppearanceSmall"/>
<TextView
a:id="@+id/select_album_year"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_below="@+id/select_album_genre"
a:layout_toRightOf="@+id/select_album_art"
a:ellipsize="end"
a:paddingRight="4dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceSmall"/>
<TextView
a:id="@+id/select_album_song_count"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_below="@+id/select_album_genre"
a:layout_below="@+id/select_album_year"
a:layout_toRightOf="@+id/select_album_art"
a:ellipsize="none"
a:paddingRight="4dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceSmall" />
a:textAppearance="?android:attr/textAppearanceSmall"/>
<TextView
a:id="@+id/select_album_duration"
@ -67,6 +78,6 @@
a:ellipsize="none"
a:paddingRight="4dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceSmall" />
a:textAppearance="?android:attr/textAppearanceSmall"/>
</RelativeLayout>

View File

@ -388,6 +388,7 @@
<string name="settings.image_loader_concurrency_11">11</string>
<string name="settings.image_loader_concurrency_12">12</string>
<string name="albumArt">albumArt</string>
<string name="common_multiple_years">Multiple Years</string>
<plurals name="select_album_n_songs">
<item quantity="zero">Aucun titre</item>

View File

@ -388,6 +388,7 @@
<string name="settings.image_loader_concurrency_11">11</string>
<string name="settings.image_loader_concurrency_12">12</string>
<string name="albumArt">albumArt</string>
<string name="common_multiple_years">Multiple Years</string>
<plurals name="select_album_n_songs">
<item quantity="zero">Nincsenek dalok</item>

View File

@ -388,6 +388,7 @@
<string name="settings.image_loader_concurrency_11">11</string>
<string name="settings.image_loader_concurrency_12">12</string>
<string name="albumArt">albumArt</string>
<string name="common_multiple_years">Multiple Years</string>
<plurals name="select_album_n_songs">
<item quantity="zero">No songs</item>

View File

@ -1325,7 +1325,7 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
artistTextView.setText(null);
downloadTrackTextView.setText(null);
downloadTotalDurationTextView.setText(null);
getImageLoader().loadImage(albumArtImageView, null, true, 0, false, false);
getImageLoader().loadImage(albumArtImageView, null, true, 0, false, true);
}
}

View File

@ -1196,11 +1196,12 @@ public class SelectAlbumActivity extends SubsonicTabActivity
int artworkSelection = random.nextInt(entries.size());
getImageLoader().loadImage(coverArtView, entries.get(artworkSelection), false, Util.getAlbumImageSize(SelectAlbumActivity.this), false, true);
TextView titleView = (TextView) header.findViewById(R.id.select_album_title);
titleView.setText(name != null ? name : getActionBarSubtitle());
AlbumHeader albumHeader = AlbumHeader.processEntries(SelectAlbumActivity.this, entries);
TextView titleView = (TextView) header.findViewById(R.id.select_album_title);
name = albumHeader.getAlbumNames().size() == 1 ? albumHeader.getAlbumNames().iterator().next() : name;
titleView.setText(name != null ? name : getActionBarSubtitle());
// Don't show a header if all entries are videos
if (albumHeader.getIsAllVideo())
{
@ -1221,6 +1222,13 @@ public class SelectAlbumActivity extends SubsonicTabActivity
genreView.setText(genre);
TextView yearView = (TextView) header.findViewById(R.id.select_album_year);
String year;
year = albumHeader.getYears().size() == 1 ? albumHeader.getYears().iterator().next().toString() : getResources().getString(R.string.common_multiple_years);
yearView.setText(year);
TextView songCountView = (TextView) header.findViewById(R.id.select_album_song_count);
String songs = getResources().getQuantityString(R.plurals.select_album_n_songs, songCount, songCount);
songCountView.setText(songs);

View File

@ -14,6 +14,8 @@ public class AlbumHeader
private Set<String> artists;
private Set<String> grandParents;
private Set<String> genres;
private Set<String> albumNames;
private Set<Integer> years;
public boolean getIsAllVideo()
{
@ -40,11 +42,24 @@ public class AlbumHeader
return this.genres;
}
public Set<String> getAlbumNames()
{
return this.albumNames;
}
public Set<Integer> getYears()
{
return this.years;
}
public AlbumHeader()
{
this.artists = new HashSet<String>();
this.grandParents = new HashSet<String>();
this.genres = new HashSet<String>();
this.albumNames = new HashSet<String>();
this.years = new HashSet<Integer>();
this.isAllVideo = true;
this.totalDuration = 0;
}
@ -83,6 +98,16 @@ public class AlbumHeader
{
albumHeader.genres.add(entry.getGenre());
}
if (entry.getAlbum() != null)
{
albumHeader.albumNames.add(entry.getAlbum());
}
if (entry.getYear() != null)
{
albumHeader.years.add(entry.getYear());
}
}
}

View File

@ -77,11 +77,11 @@ public class CacheCleaner
}
}
private static void deleteEmptyDirs(Iterable<File> dirs, Collection<File> undeletable)
private static void deleteEmptyDirs(Iterable<File> dirs, Collection<File> doNotDelete)
{
for (File dir : dirs)
{
if (undeletable.contains(dir))
if (doNotDelete.contains(dir))
{
continue;
}
@ -114,8 +114,8 @@ public class CacheCleaner
}
long cacheSizeBytes = Util.getCacheSizeMB(context) * 1024L * 1024L;
long bytesUsedBySubsonic = 0L;
for (File file : files)
{
bytesUsedBySubsonic += file.length();
@ -140,7 +140,7 @@ public class CacheCleaner
return bytesToDelete;
}
private static void deleteFiles(Collection<File> files, Collection<File> undeletable, long bytesToDelete, boolean deletePartials)
private static void deleteFiles(Collection<File> files, Collection<File> doNotDelete, long bytesToDelete, boolean deletePartials)
{
if (files.isEmpty())
{
@ -154,9 +154,10 @@ public class CacheCleaner
if (bytesToDelete > bytesDeleted || (deletePartials && (file.getName().endsWith(".partial") || file.getName().contains(".partial."))))
{
if (!undeletable.contains(file) && !file.getName().equals(Constants.ALBUM_ART_FILE))
if (!doNotDelete.contains(file) && !file.getName().equals(Constants.ALBUM_ART_FILE))
{
long size = file.length();
if (Util.delete(file))
{
bytesDeleted += size;
@ -174,6 +175,7 @@ public class CacheCleaner
{
String name = file.getName();
boolean isCacheFile = name.endsWith(".partial") || name.contains(".partial.") || name.endsWith(".complete") || name.contains(".complete.");
if (isCacheFile)
{
files.add(file);
@ -186,6 +188,7 @@ public class CacheCleaner
{
findCandidatesForDeletion(child, files, dirs);
}
dirs.add(file);
}
}
@ -212,18 +215,18 @@ public class CacheCleaner
});
}
private Set<File> findUndeletableFiles()
private Set<File> findFilesToNotDelete()
{
Set<File> undeletable = new HashSet<File>(5);
Set<File> filesToNotDelete = new HashSet<File>(5);
for (DownloadFile downloadFile : downloadService.getDownloads())
{
undeletable.add(downloadFile.getPartialFile());
undeletable.add(downloadFile.getCompleteFile());
filesToNotDelete.add(downloadFile.getPartialFile());
filesToNotDelete.add(downloadFile.getCompleteFile());
}
undeletable.add(FileUtil.getMusicDirectory(context));
return undeletable;
filesToNotDelete.add(FileUtil.getMusicDirectory(context));
return filesToNotDelete;
}
private class BackgroundCleanup extends AsyncTask<Void, Void, Void>
@ -246,10 +249,10 @@ public class CacheCleaner
findCandidatesForDeletion(FileUtil.getMusicDirectory(context), files, dirs);
sortByAscendingModificationTime(files);
Set<File> undeletable = findUndeletableFiles();
Set<File> filesToNotDelete = findFilesToNotDelete();
deleteFiles(files, undeletable, getMinimumDelete(files), true);
deleteEmptyDirs(dirs, undeletable);
deleteFiles(files, filesToNotDelete, getMinimumDelete(files), true);
deleteEmptyDirs(dirs, filesToNotDelete);
}
catch (RuntimeException x)
{
@ -282,8 +285,8 @@ public class CacheCleaner
if (bytesToDelete > 0L)
{
sortByAscendingModificationTime(files);
Set<File> undeletable = findUndeletableFiles();
deleteFiles(files, undeletable, bytesToDelete, false);
Set<File> filesToNotDelete = findFilesToNotDelete();
deleteFiles(files, filesToNotDelete, bytesToDelete, false);
}
}
catch (RuntimeException x)

View File

@ -38,6 +38,7 @@ import com.thejoshwa.ultrasonic.androidapp.service.MusicServiceFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
@ -98,7 +99,7 @@ public class ImageLoader implements Runnable
{
running.set(true);
threads = new ArrayList<Thread>(this.concurrency);
threads = Collections.synchronizedCollection(new ArrayList<Thread>(this.concurrency));
for (int i = 0; i < this.concurrency; i++)
{
@ -209,9 +210,10 @@ public class ImageLoader implements Runnable
MusicDirectory.Entry tagEntry = (MusicDirectory.Entry) view.getTag();
// Only apply image to the view if the view is intended for this entry
if (entry != null && tagEntry != null && !entry.equals(tagEntry))
{
Log.i(TAG, "Skipping entry");
Log.i(TAG, "View is no longer valid, not setting ImageBitmap");
return;
}