mirror of
https://github.com/ultrasonic/ultrasonic
synced 2025-02-27 08:57:44 +01:00
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:
parent
4389698d7f
commit
36167e5ab9
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<RelativeLayout xmlns:a="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:a="http://schemas.android.com/apk/res/android"
|
||||||
a:layout_width="fill_parent"
|
a:layout_width="fill_parent"
|
||||||
a:layout_height="wrap_content" >
|
a:layout_height="wrap_content">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
a:id="@+id/select_album_art"
|
a:id="@+id/select_album_art"
|
||||||
@ -12,7 +12,7 @@
|
|||||||
a:layout_marginRight="10dip"
|
a:layout_marginRight="10dip"
|
||||||
a:contentDescription="@null"
|
a:contentDescription="@null"
|
||||||
a:scaleType="fitCenter"
|
a:scaleType="fitCenter"
|
||||||
a:src="@drawable/unknown_album_large" />
|
a:src="@drawable/unknown_album_large"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
a:id="@+id/select_album_title"
|
a:id="@+id/select_album_title"
|
||||||
@ -23,7 +23,7 @@
|
|||||||
a:paddingRight="4dip"
|
a:paddingRight="4dip"
|
||||||
a:paddingTop="10dip"
|
a:paddingTop="10dip"
|
||||||
a:singleLine="true"
|
a:singleLine="true"
|
||||||
a:textAppearance="?android:attr/textAppearanceMedium" />
|
a:textAppearance="?android:attr/textAppearanceMedium"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
a:id="@+id/select_album_artist"
|
a:id="@+id/select_album_artist"
|
||||||
@ -34,7 +34,7 @@
|
|||||||
a:ellipsize="end"
|
a:ellipsize="end"
|
||||||
a:paddingRight="4dip"
|
a:paddingRight="4dip"
|
||||||
a:singleLine="true"
|
a:singleLine="true"
|
||||||
a:textAppearance="?android:attr/textAppearanceSmall" />
|
a:textAppearance="?android:attr/textAppearanceSmall"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
a:id="@+id/select_album_genre"
|
a:id="@+id/select_album_genre"
|
||||||
@ -45,18 +45,29 @@
|
|||||||
a:ellipsize="end"
|
a:ellipsize="end"
|
||||||
a:paddingRight="4dip"
|
a:paddingRight="4dip"
|
||||||
a:singleLine="true"
|
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
|
<TextView
|
||||||
a:id="@+id/select_album_song_count"
|
a:id="@+id/select_album_song_count"
|
||||||
a:layout_width="wrap_content"
|
a:layout_width="wrap_content"
|
||||||
a:layout_height="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:layout_toRightOf="@+id/select_album_art"
|
||||||
a:ellipsize="none"
|
a:ellipsize="none"
|
||||||
a:paddingRight="4dip"
|
a:paddingRight="4dip"
|
||||||
a:singleLine="true"
|
a:singleLine="true"
|
||||||
a:textAppearance="?android:attr/textAppearanceSmall" />
|
a:textAppearance="?android:attr/textAppearanceSmall"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
a:id="@+id/select_album_duration"
|
a:id="@+id/select_album_duration"
|
||||||
@ -67,6 +78,6 @@
|
|||||||
a:ellipsize="none"
|
a:ellipsize="none"
|
||||||
a:paddingRight="4dip"
|
a:paddingRight="4dip"
|
||||||
a:singleLine="true"
|
a:singleLine="true"
|
||||||
a:textAppearance="?android:attr/textAppearanceSmall" />
|
a:textAppearance="?android:attr/textAppearanceSmall"/>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
@ -388,6 +388,7 @@
|
|||||||
<string name="settings.image_loader_concurrency_11">11</string>
|
<string name="settings.image_loader_concurrency_11">11</string>
|
||||||
<string name="settings.image_loader_concurrency_12">12</string>
|
<string name="settings.image_loader_concurrency_12">12</string>
|
||||||
<string name="albumArt">albumArt</string>
|
<string name="albumArt">albumArt</string>
|
||||||
|
<string name="common_multiple_years">Multiple Years</string>
|
||||||
|
|
||||||
<plurals name="select_album_n_songs">
|
<plurals name="select_album_n_songs">
|
||||||
<item quantity="zero">Aucun titre</item>
|
<item quantity="zero">Aucun titre</item>
|
||||||
|
@ -388,6 +388,7 @@
|
|||||||
<string name="settings.image_loader_concurrency_11">11</string>
|
<string name="settings.image_loader_concurrency_11">11</string>
|
||||||
<string name="settings.image_loader_concurrency_12">12</string>
|
<string name="settings.image_loader_concurrency_12">12</string>
|
||||||
<string name="albumArt">albumArt</string>
|
<string name="albumArt">albumArt</string>
|
||||||
|
<string name="common_multiple_years">Multiple Years</string>
|
||||||
|
|
||||||
<plurals name="select_album_n_songs">
|
<plurals name="select_album_n_songs">
|
||||||
<item quantity="zero">Nincsenek dalok</item>
|
<item quantity="zero">Nincsenek dalok</item>
|
||||||
|
@ -388,6 +388,7 @@
|
|||||||
<string name="settings.image_loader_concurrency_11">11</string>
|
<string name="settings.image_loader_concurrency_11">11</string>
|
||||||
<string name="settings.image_loader_concurrency_12">12</string>
|
<string name="settings.image_loader_concurrency_12">12</string>
|
||||||
<string name="albumArt">albumArt</string>
|
<string name="albumArt">albumArt</string>
|
||||||
|
<string name="common_multiple_years">Multiple Years</string>
|
||||||
|
|
||||||
<plurals name="select_album_n_songs">
|
<plurals name="select_album_n_songs">
|
||||||
<item quantity="zero">No songs</item>
|
<item quantity="zero">No songs</item>
|
||||||
|
@ -1325,7 +1325,7 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
|
|||||||
artistTextView.setText(null);
|
artistTextView.setText(null);
|
||||||
downloadTrackTextView.setText(null);
|
downloadTrackTextView.setText(null);
|
||||||
downloadTotalDurationTextView.setText(null);
|
downloadTotalDurationTextView.setText(null);
|
||||||
getImageLoader().loadImage(albumArtImageView, null, true, 0, false, false);
|
getImageLoader().loadImage(albumArtImageView, null, true, 0, false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1196,11 +1196,12 @@ public class SelectAlbumActivity extends SubsonicTabActivity
|
|||||||
int artworkSelection = random.nextInt(entries.size());
|
int artworkSelection = random.nextInt(entries.size());
|
||||||
getImageLoader().loadImage(coverArtView, entries.get(artworkSelection), false, Util.getAlbumImageSize(SelectAlbumActivity.this), false, true);
|
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);
|
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
|
// Don't show a header if all entries are videos
|
||||||
if (albumHeader.getIsAllVideo())
|
if (albumHeader.getIsAllVideo())
|
||||||
{
|
{
|
||||||
@ -1221,6 +1222,13 @@ public class SelectAlbumActivity extends SubsonicTabActivity
|
|||||||
|
|
||||||
genreView.setText(genre);
|
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);
|
TextView songCountView = (TextView) header.findViewById(R.id.select_album_song_count);
|
||||||
String songs = getResources().getQuantityString(R.plurals.select_album_n_songs, songCount, songCount);
|
String songs = getResources().getQuantityString(R.plurals.select_album_n_songs, songCount, songCount);
|
||||||
songCountView.setText(songs);
|
songCountView.setText(songs);
|
||||||
|
@ -14,6 +14,8 @@ public class AlbumHeader
|
|||||||
private Set<String> artists;
|
private Set<String> artists;
|
||||||
private Set<String> grandParents;
|
private Set<String> grandParents;
|
||||||
private Set<String> genres;
|
private Set<String> genres;
|
||||||
|
private Set<String> albumNames;
|
||||||
|
private Set<Integer> years;
|
||||||
|
|
||||||
public boolean getIsAllVideo()
|
public boolean getIsAllVideo()
|
||||||
{
|
{
|
||||||
@ -40,11 +42,24 @@ public class AlbumHeader
|
|||||||
return this.genres;
|
return this.genres;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<String> getAlbumNames()
|
||||||
|
{
|
||||||
|
return this.albumNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Integer> getYears()
|
||||||
|
{
|
||||||
|
return this.years;
|
||||||
|
}
|
||||||
|
|
||||||
public AlbumHeader()
|
public AlbumHeader()
|
||||||
{
|
{
|
||||||
this.artists = new HashSet<String>();
|
this.artists = new HashSet<String>();
|
||||||
this.grandParents = new HashSet<String>();
|
this.grandParents = new HashSet<String>();
|
||||||
this.genres = new HashSet<String>();
|
this.genres = new HashSet<String>();
|
||||||
|
this.albumNames = new HashSet<String>();
|
||||||
|
this.years = new HashSet<Integer>();
|
||||||
|
|
||||||
this.isAllVideo = true;
|
this.isAllVideo = true;
|
||||||
this.totalDuration = 0;
|
this.totalDuration = 0;
|
||||||
}
|
}
|
||||||
@ -83,6 +98,16 @@ public class AlbumHeader
|
|||||||
{
|
{
|
||||||
albumHeader.genres.add(entry.getGenre());
|
albumHeader.genres.add(entry.getGenre());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (entry.getAlbum() != null)
|
||||||
|
{
|
||||||
|
albumHeader.albumNames.add(entry.getAlbum());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.getYear() != null)
|
||||||
|
{
|
||||||
|
albumHeader.years.add(entry.getYear());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
for (File dir : dirs)
|
||||||
{
|
{
|
||||||
if (undeletable.contains(dir))
|
if (doNotDelete.contains(dir))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -114,8 +114,8 @@ public class CacheCleaner
|
|||||||
}
|
}
|
||||||
|
|
||||||
long cacheSizeBytes = Util.getCacheSizeMB(context) * 1024L * 1024L;
|
long cacheSizeBytes = Util.getCacheSizeMB(context) * 1024L * 1024L;
|
||||||
|
|
||||||
long bytesUsedBySubsonic = 0L;
|
long bytesUsedBySubsonic = 0L;
|
||||||
|
|
||||||
for (File file : files)
|
for (File file : files)
|
||||||
{
|
{
|
||||||
bytesUsedBySubsonic += file.length();
|
bytesUsedBySubsonic += file.length();
|
||||||
@ -140,7 +140,7 @@ public class CacheCleaner
|
|||||||
return bytesToDelete;
|
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())
|
if (files.isEmpty())
|
||||||
{
|
{
|
||||||
@ -154,9 +154,10 @@ public class CacheCleaner
|
|||||||
|
|
||||||
if (bytesToDelete > bytesDeleted || (deletePartials && (file.getName().endsWith(".partial") || file.getName().contains(".partial."))))
|
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();
|
long size = file.length();
|
||||||
|
|
||||||
if (Util.delete(file))
|
if (Util.delete(file))
|
||||||
{
|
{
|
||||||
bytesDeleted += size;
|
bytesDeleted += size;
|
||||||
@ -174,6 +175,7 @@ public class CacheCleaner
|
|||||||
{
|
{
|
||||||
String name = file.getName();
|
String name = file.getName();
|
||||||
boolean isCacheFile = name.endsWith(".partial") || name.contains(".partial.") || name.endsWith(".complete") || name.contains(".complete.");
|
boolean isCacheFile = name.endsWith(".partial") || name.contains(".partial.") || name.endsWith(".complete") || name.contains(".complete.");
|
||||||
|
|
||||||
if (isCacheFile)
|
if (isCacheFile)
|
||||||
{
|
{
|
||||||
files.add(file);
|
files.add(file);
|
||||||
@ -186,6 +188,7 @@ public class CacheCleaner
|
|||||||
{
|
{
|
||||||
findCandidatesForDeletion(child, files, dirs);
|
findCandidatesForDeletion(child, files, dirs);
|
||||||
}
|
}
|
||||||
|
|
||||||
dirs.add(file);
|
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())
|
for (DownloadFile downloadFile : downloadService.getDownloads())
|
||||||
{
|
{
|
||||||
undeletable.add(downloadFile.getPartialFile());
|
filesToNotDelete.add(downloadFile.getPartialFile());
|
||||||
undeletable.add(downloadFile.getCompleteFile());
|
filesToNotDelete.add(downloadFile.getCompleteFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
undeletable.add(FileUtil.getMusicDirectory(context));
|
filesToNotDelete.add(FileUtil.getMusicDirectory(context));
|
||||||
return undeletable;
|
return filesToNotDelete;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BackgroundCleanup extends AsyncTask<Void, Void, Void>
|
private class BackgroundCleanup extends AsyncTask<Void, Void, Void>
|
||||||
@ -246,10 +249,10 @@ public class CacheCleaner
|
|||||||
findCandidatesForDeletion(FileUtil.getMusicDirectory(context), files, dirs);
|
findCandidatesForDeletion(FileUtil.getMusicDirectory(context), files, dirs);
|
||||||
sortByAscendingModificationTime(files);
|
sortByAscendingModificationTime(files);
|
||||||
|
|
||||||
Set<File> undeletable = findUndeletableFiles();
|
Set<File> filesToNotDelete = findFilesToNotDelete();
|
||||||
|
|
||||||
deleteFiles(files, undeletable, getMinimumDelete(files), true);
|
deleteFiles(files, filesToNotDelete, getMinimumDelete(files), true);
|
||||||
deleteEmptyDirs(dirs, undeletable);
|
deleteEmptyDirs(dirs, filesToNotDelete);
|
||||||
}
|
}
|
||||||
catch (RuntimeException x)
|
catch (RuntimeException x)
|
||||||
{
|
{
|
||||||
@ -282,8 +285,8 @@ public class CacheCleaner
|
|||||||
if (bytesToDelete > 0L)
|
if (bytesToDelete > 0L)
|
||||||
{
|
{
|
||||||
sortByAscendingModificationTime(files);
|
sortByAscendingModificationTime(files);
|
||||||
Set<File> undeletable = findUndeletableFiles();
|
Set<File> filesToNotDelete = findFilesToNotDelete();
|
||||||
deleteFiles(files, undeletable, bytesToDelete, false);
|
deleteFiles(files, filesToNotDelete, bytesToDelete, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (RuntimeException x)
|
catch (RuntimeException x)
|
||||||
|
@ -38,6 +38,7 @@ import com.thejoshwa.ultrasonic.androidapp.service.MusicServiceFactory;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
@ -98,7 +99,7 @@ public class ImageLoader implements Runnable
|
|||||||
{
|
{
|
||||||
running.set(true);
|
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++)
|
for (int i = 0; i < this.concurrency; i++)
|
||||||
{
|
{
|
||||||
@ -209,9 +210,10 @@ public class ImageLoader implements Runnable
|
|||||||
|
|
||||||
MusicDirectory.Entry tagEntry = (MusicDirectory.Entry) view.getTag();
|
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))
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user