diff --git a/res/values/translatable.xml b/res/values/translatable.xml
index aca08f81..14f692d3 100644
--- a/res/values/translatable.xml
+++ b/res/values/translatable.xml
@@ -109,6 +109,8 @@ THE SOFTWARE.
Artists
Albums
+ Album Artists
+ Composers
Tracks
Playlists
Genres
diff --git a/src/ch/blinkenlights/android/medialibrary/MediaLibrary.java b/src/ch/blinkenlights/android/medialibrary/MediaLibrary.java
index 4a937010..fc446a26 100644
--- a/src/ch/blinkenlights/android/medialibrary/MediaLibrary.java
+++ b/src/ch/blinkenlights/android/medialibrary/MediaLibrary.java
@@ -29,19 +29,22 @@ import java.io.File;
public class MediaLibrary {
- public static final String TABLE_SONGS = "songs";
- public static final String TABLE_ALBUMS = "albums";
- public static final String TABLE_CONTRIBUTORS = "contributors";
- public static final String TABLE_CONTRIBUTORS_SONGS = "contributors_songs";
- public static final String TABLE_GENRES = "genres";
- public static final String TABLE_GENRES_SONGS = "genres_songs";
- public static final String TABLE_PLAYLISTS = "playlists";
- public static final String TABLE_PLAYLISTS_SONGS = "playlists_songs";
- public static final String TABLE_PREFERENCES = "preferences";
- public static final String VIEW_ARTISTS = "_artists";
- public static final String VIEW_ALBUMS_ARTISTS = "_albums_artists";
- public static final String VIEW_SONGS_ALBUMS_ARTISTS = "_songs_albums_artists";
- public static final String VIEW_PLAYLIST_SONGS = "_playlists_songs";
+ public static final String TABLE_SONGS = "songs";
+ public static final String TABLE_ALBUMS = "albums";
+ public static final String TABLE_CONTRIBUTORS = "contributors";
+ public static final String TABLE_CONTRIBUTORS_SONGS = "contributors_songs";
+ public static final String TABLE_GENRES = "genres";
+ public static final String TABLE_GENRES_SONGS = "genres_songs";
+ public static final String TABLE_PLAYLISTS = "playlists";
+ public static final String TABLE_PLAYLISTS_SONGS = "playlists_songs";
+ public static final String TABLE_PREFERENCES = "preferences";
+ public static final String VIEW_ARTISTS = "_artists";
+ public static final String VIEW_ALBUMARTISTS = "_albumartists";
+ public static final String VIEW_COMPOSERS = "_composers";
+ public static final String VIEW_ALBUMS_ARTISTS = "_albums_artists";
+ public static final String VIEW_SONGS_ALBUMS_ARTISTS = "_songs_albums_artists";
+ public static final String VIEW_SONGS_ALBUMS_ARTISTS_HUGE = "_songs_albums_artists_huge";
+ public static final String VIEW_PLAYLIST_SONGS = "_playlists_songs";
public static final int ROLE_ARTIST = 0;
public static final int ROLE_COMPOSER = 1;
@@ -561,6 +564,7 @@ public class MediaLibrary {
* The mtime of this item
*/
String MTIME = "mtime";
+
/**
* ONLY IN VIEWS - the artist
*/
@@ -573,6 +577,33 @@ public class MediaLibrary {
* ONLY IN VIEWS - the artist id
*/
String ARTIST_ID = "artist_id";
+
+ /**
+ * ONLY IN VIEWS - the albumartist
+ */
+ String ALBUMARTIST = "albumartist";
+ /**
+ * ONLY IN VIEWS - the albumartist_sort key
+ */
+ String ALBUMARTIST_SORT = "albumartist_sort";
+ /**
+ * ONLY IN VIEWS - the albumartist id
+ */
+ String ALBUMARTIST_ID = "albumartist_id";
+
+ /**
+ * ONLY IN VIEWS - the composer
+ */
+ String COMPOSER = "composer";
+ /**
+ * ONLY IN VIEWS - the composer_sort key
+ */
+ String COMPOSER_SORT = "composer_sort";
+ /**
+ * ONLY IN VIEWS - the composer id
+ */
+ String COMPOSER_ID = "composer_id";
+
}
// Songs <-> Contributor mapping
diff --git a/src/ch/blinkenlights/android/medialibrary/MediaLibraryBackend.java b/src/ch/blinkenlights/android/medialibrary/MediaLibraryBackend.java
index 6280bd57..a6998d02 100644
--- a/src/ch/blinkenlights/android/medialibrary/MediaLibraryBackend.java
+++ b/src/ch/blinkenlights/android/medialibrary/MediaLibraryBackend.java
@@ -35,7 +35,7 @@ public class MediaLibraryBackend extends SQLiteOpenHelper {
/**
* The database version we are using
*/
- private static final int DATABASE_VERSION = 20170211;
+ private static final int DATABASE_VERSION = 20170217;
/**
* on-disk file to store the database
*/
@@ -48,6 +48,14 @@ public class MediaLibraryBackend extends SQLiteOpenHelper {
* Regexp to detect costy artist_id queries which we can optimize
*/
private static final Pattern sQueryMatchArtistSearch = Pattern.compile("(^|.+ )"+MediaLibrary.ContributorColumns.ARTIST_ID+"=(\\d+)$");
+ /**
+ * Regexp to detect costy albumartist_id queries which we can optimize
+ */
+ private static final Pattern sQueryMatchAlbArtistSearch = Pattern.compile("(^|.+ )"+MediaLibrary.ContributorColumns.ALBUMARTIST_ID+"=(\\d+)$");
+ /**
+ * Regexp to detect costy composer_id queries which we can optimize
+ */
+ private static final Pattern sQueryMatchComposerSearch = Pattern.compile("(^|.+ )"+MediaLibrary.ContributorColumns.COMPOSER_ID+"=(\\d+)$");
/**
* Constructor for the MediaLibraryBackend helper
@@ -232,29 +240,36 @@ public class MediaLibraryBackend extends SQLiteOpenHelper {
*/
Cursor query (boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) {
+ if (MediaLibrary.VIEW_SONGS_ALBUMS_ARTISTS_HUGE.equals(table)) {
+ Log.v("VanillaMusic", "+++ warning : using HUGE table in genquery!");
+ }
+
if (selection != null) {
if (MediaLibrary.VIEW_SONGS_ALBUMS_ARTISTS.equals(table)) {
// artist matches in the song-view are costy: try to give sqlite a hint
- Matcher artistMatch = sQueryMatchArtistSearch.matcher(selection);
- if (artistMatch.matches()) {
- selection = artistMatch.group(1);
- final String artistId = artistMatch.group(2);
+ String[] contributorMatch = extractVirtualColumn(selection);
+ if (contributorMatch != null) {
+ selection = contributorMatch[0];
+ final String contributorId = contributorMatch[1];
+ final String contributorRole = contributorMatch[2];
selection += MediaLibrary.SongColumns._ID+" IN (SELECT "+MediaLibrary.ContributorSongColumns.SONG_ID+" FROM "+MediaLibrary.TABLE_CONTRIBUTORS_SONGS+" WHERE "
- + MediaLibrary.ContributorSongColumns.ROLE+"=0 AND "+MediaLibrary.ContributorSongColumns._CONTRIBUTOR_ID+"="+artistId+")";
+ + MediaLibrary.ContributorSongColumns.ROLE+"="+contributorRole+" AND "+MediaLibrary.ContributorSongColumns._CONTRIBUTOR_ID+"="+contributorId+")";
}
}
if (MediaLibrary.VIEW_ALBUMS_ARTISTS.equals(table)) {
// looking up artists by albums will magically return every album where this
// artist has at least one item (while still using the primary_artist_id as the artist key)
- Matcher artistMatch = sQueryMatchArtistSearch.matcher(selection);
- if (artistMatch.matches()) {
- selection = artistMatch.group(1);
- final String artistId = artistMatch.group(2);
+ String[] contributorMatch = extractVirtualColumn(selection);
+ if (contributorMatch != null) {
+ selection = contributorMatch[0];
+ final String contributorId = contributorMatch[1];
+ final String contributorRole = contributorMatch[2];
+
selection += MediaLibrary.SongColumns._ID+" IN (SELECT DISTINCT "+MediaLibrary.SongColumns.ALBUM_ID+" FROM "+MediaLibrary.TABLE_SONGS+" WHERE "
+ MediaLibrary.SongColumns._ID+" IN (SELECT "+MediaLibrary.ContributorSongColumns.SONG_ID+" FROM "+MediaLibrary.TABLE_CONTRIBUTORS_SONGS+" WHERE "
- + MediaLibrary.ContributorSongColumns.ROLE+"=0 AND "+MediaLibrary.ContributorSongColumns._CONTRIBUTOR_ID+"="+artistId+"))";
+ + MediaLibrary.ContributorSongColumns.ROLE+"="+contributorRole+" AND "+MediaLibrary.ContributorSongColumns._CONTRIBUTOR_ID+"="+contributorId+"))";
}
}
@@ -265,17 +280,33 @@ public class MediaLibraryBackend extends SQLiteOpenHelper {
final String genreId = genreMatch.group(2); // and extract the searched genre id
final String songsQuery = buildSongIdFromGenreSelect(genreId);
- if(table.equals(MediaLibrary.VIEW_SONGS_ALBUMS_ARTISTS)) {
+ if(table.equals(MediaLibrary.VIEW_SONGS_ALBUMS_ARTISTS) ||
+ table.equals(MediaLibrary.VIEW_SONGS_ALBUMS_ARTISTS_HUGE) ) {
selection += MediaLibrary.SongColumns._ID+" IN ("+songsQuery+") ";
}
- if (table.equals(MediaLibrary.VIEW_ARTISTS)) {
- selection += MediaLibrary.ContributorColumns.ARTIST_ID+" IN ("+ buildSongIdFromGenreSelect(MediaLibrary.ContributorColumns.ARTIST_ID, songsQuery)+") ";
+ if (table.equals(MediaLibrary.VIEW_ALBUMS_ARTISTS)) {
+ selection += MediaLibrary.AlbumColumns._ID+" IN ("+
+ buildSongIdFromGenreSelect(MediaLibrary.SongColumns.ALBUM_ID, MediaLibrary.VIEW_SONGS_ALBUMS_ARTISTS, songsQuery)+") ";
}
- if (table.equals(MediaLibrary.VIEW_ALBUMS_ARTISTS)) {
- selection += MediaLibrary.AlbumColumns._ID+" IN ("+ buildSongIdFromGenreSelect(MediaLibrary.SongColumns.ALBUM_ID, songsQuery)+") ";
+ if (table.equals(MediaLibrary.VIEW_ARTISTS)) {
+ selection += MediaLibrary.ContributorColumns.ARTIST_ID+" IN ("+
+ buildSongIdFromGenreSelect(MediaLibrary.ContributorColumns.ARTIST_ID, MediaLibrary.VIEW_SONGS_ALBUMS_ARTISTS, songsQuery)+") ";
}
+
+ if (table.equals(MediaLibrary.VIEW_ALBUMARTISTS)) {
+ selection += MediaLibrary.ContributorColumns.ALBUMARTIST_ID+" IN ("+
+ buildSongIdFromGenreSelect(MediaLibrary.ContributorColumns.ALBUMARTIST_ID, MediaLibrary.VIEW_SONGS_ALBUMS_ARTISTS_HUGE, songsQuery)+") ";
+ Log.v("VanillaMusic", "+++ warning: huge genrequery for albumartist!");
+ }
+
+ if (table.equals(MediaLibrary.VIEW_COMPOSERS)) {
+ selection += MediaLibrary.ContributorColumns.COMPOSER_ID+" IN ("+
+ buildSongIdFromGenreSelect(MediaLibrary.ContributorColumns.COMPOSER_ID, MediaLibrary.VIEW_SONGS_ALBUMS_ARTISTS_HUGE, songsQuery)+") ";
+ Log.v("VanillaMusic", "+++ warning: huge genrequery composer!");
+ }
+
}
}
@@ -294,6 +325,26 @@ public class MediaLibraryBackend extends SQLiteOpenHelper {
return cursor;
}
+ /**
+ * Detects queries for artists, composers and albumartists and returns the
+ * role of the contributor.
+ *
+ * @param sql the raw sql query
+ * @return String[]{ sql-part, contributor-id, contributor-role }
+ */
+ private String[] extractVirtualColumn(String sql) {
+ final Pattern[] pattern = new Pattern[]{ sQueryMatchArtistSearch, sQueryMatchComposerSearch, sQueryMatchAlbArtistSearch };
+ final int[] roles = { MediaLibrary.ROLE_ARTIST, MediaLibrary.ROLE_COMPOSER, MediaLibrary.ROLE_ALBUMARTIST };
+
+ for (int i=0; i < roles.length; i++) {
+ Matcher matcher = pattern[i].matcher(sql);
+ if (matcher.matches()) {
+ return new String[]{ matcher.group(1), matcher.group(2), String.format("%d", roles[i]) };
+ }
+ }
+ return null;
+ }
+
/**
* Returns a select query to get all songs from a genre
*
@@ -309,11 +360,12 @@ public class MediaLibraryBackend extends SQLiteOpenHelper {
* Returns a select query to get artists or albums from a genre
*
* @param target the target to query
+ * @param table the table to query
* @param genreSelect the select string generated by buildSongIdFromGenreSelect
* @return an SQL string
*/
- private String buildSongIdFromGenreSelect(String target, String genreSelect) {
- return "SELECT "+target+" FROM "+MediaLibrary.VIEW_SONGS_ALBUMS_ARTISTS+" WHERE "
+ private String buildSongIdFromGenreSelect(String target, String table, String genreSelect) {
+ return "SELECT "+target+" FROM "+ table +" WHERE "
+MediaLibrary.SongColumns._ID+" IN ("+genreSelect+") GROUP BY "+target;
}
diff --git a/src/ch/blinkenlights/android/medialibrary/MediaSchema.java b/src/ch/blinkenlights/android/medialibrary/MediaSchema.java
index 6cbc8bc2..91d6ed8f 100644
--- a/src/ch/blinkenlights/android/medialibrary/MediaSchema.java
+++ b/src/ch/blinkenlights/android/medialibrary/MediaSchema.java
@@ -145,7 +145,22 @@ public class MediaSchema {
+",_artist."+MediaLibrary.ContributorColumns._ID+" AS "+MediaLibrary.ContributorColumns.ARTIST_ID;
/**
- * View which includes song, album and artist information
+ * Additional columns to select for albumartist info
+ */
+ private static final String VIEW_ALBUMARTIST_SELECT = "_albumartist."+MediaLibrary.ContributorColumns._CONTRIBUTOR+" AS "+MediaLibrary.ContributorColumns.ALBUMARTIST
+ +",_albumartist."+MediaLibrary.ContributorColumns._CONTRIBUTOR_SORT+" AS "+MediaLibrary.ContributorColumns.ALBUMARTIST_SORT
+ +",_albumartist."+MediaLibrary.ContributorColumns._ID+" AS "+MediaLibrary.ContributorColumns.ALBUMARTIST_ID;
+
+ /**
+ * Additional columns to select for composer info
+ */
+ private static final String VIEW_COMPOSER_SELECT = "_composer."+MediaLibrary.ContributorColumns._CONTRIBUTOR+" AS "+MediaLibrary.ContributorColumns.COMPOSER
+ +",_composer."+MediaLibrary.ContributorColumns._CONTRIBUTOR_SORT+" AS "+MediaLibrary.ContributorColumns.COMPOSER_SORT
+ +",_composer."+MediaLibrary.ContributorColumns._ID+" AS "+MediaLibrary.ContributorColumns.COMPOSER_ID;
+
+
+ /**
+ * View which includes song, album and artist information, enough for a filled song projection
*/
private static final String VIEW_CREATE_SONGS_ALBUMS_ARTISTS = "CREATE VIEW "+ MediaLibrary.VIEW_SONGS_ALBUMS_ARTISTS+ " AS "
+ "SELECT *, " + VIEW_ARTIST_SELECT + " FROM " + MediaLibrary.TABLE_SONGS
@@ -155,6 +170,26 @@ public class MediaSchema {
+" LEFT JOIN "+MediaLibrary.TABLE_CONTRIBUTORS+" AS _artist ON _artist."+MediaLibrary.ContributorColumns._ID+" = "+MediaLibrary.TABLE_CONTRIBUTORS_SONGS+"."+MediaLibrary.ContributorSongColumns._CONTRIBUTOR_ID
+" ;";
+ /**
+ * View wich includes SONGS_ALBUMS_ARTISTS and any other contributors
+ * This view should only be used if needed as the SQL query is pretty expensive
+ */
+ private static final String VIEW_CREATE_SONGS_ALBUMS_ARTISTS_HUGE = "CREATE VIEW "+ MediaLibrary.VIEW_SONGS_ALBUMS_ARTISTS_HUGE+" AS "
+ + "SELECT *, "+ VIEW_ALBUMARTIST_SELECT +", "+ VIEW_COMPOSER_SELECT +" FROM "+MediaLibrary.VIEW_SONGS_ALBUMS_ARTISTS
+ // albumartists
+ +" LEFT JOIN "+MediaLibrary.TABLE_CONTRIBUTORS_SONGS+" as __albumartists"
+ +" ON __albumartists."+MediaLibrary.ContributorSongColumns.ROLE+"="+MediaLibrary.ROLE_ALBUMARTIST
+ +" AND __albumartists."+MediaLibrary.ContributorSongColumns.SONG_ID+" = "+MediaLibrary.VIEW_SONGS_ALBUMS_ARTISTS+"."+MediaLibrary.SongColumns._ID
+ +" LEFT JOIN "+MediaLibrary.TABLE_CONTRIBUTORS+" AS _albumartist ON"
+ +" _albumartist."+MediaLibrary.ContributorColumns._ID+" = __albumartists."+MediaLibrary.ContributorSongColumns._CONTRIBUTOR_ID
+ // composers
+ +" LEFT JOIN "+MediaLibrary.TABLE_CONTRIBUTORS_SONGS+" as __composers"
+ +" ON __composers."+MediaLibrary.ContributorSongColumns.ROLE+"="+MediaLibrary.ROLE_COMPOSER
+ +" AND __composers."+MediaLibrary.ContributorSongColumns.SONG_ID+" = "+MediaLibrary.VIEW_SONGS_ALBUMS_ARTISTS+"."+MediaLibrary.SongColumns._ID
+ +" LEFT JOIN "+MediaLibrary.TABLE_CONTRIBUTORS+" AS _composer ON"
+ +" _composer."+MediaLibrary.ContributorColumns._ID+" = __composers."+MediaLibrary.ContributorSongColumns._CONTRIBUTOR_ID
+ +" ;";
+
/**
* View which includes album and artist information
*/
@@ -173,6 +208,24 @@ public class MediaSchema {
+" WHERE "+MediaLibrary.ContributorSongColumns.ROLE+"="+MediaLibrary.ROLE_ARTIST+" GROUP BY "+MediaLibrary.ContributorSongColumns._CONTRIBUTOR_ID+")"
+" ;";
+ /**
+ * View which includes albumArtists information
+ */
+ private static final String VIEW_CREATE_ALBUMARTISTS = "CREATE VIEW "+ MediaLibrary.VIEW_ALBUMARTISTS+ " AS "
+ + "SELECT *, " + VIEW_ALBUMARTIST_SELECT + " FROM "+MediaLibrary.TABLE_CONTRIBUTORS+" AS _albumartist WHERE "+MediaLibrary.ContributorColumns._ID+" IN "
+ +" (SELECT "+MediaLibrary.ContributorSongColumns._CONTRIBUTOR_ID+" FROM "+MediaLibrary.TABLE_CONTRIBUTORS_SONGS
+ +" WHERE "+MediaLibrary.ContributorSongColumns.ROLE+"="+MediaLibrary.ROLE_ALBUMARTIST+" GROUP BY "+MediaLibrary.ContributorSongColumns._CONTRIBUTOR_ID+")"
+ +" ;";
+
+ /**
+ * View which includes composer information
+ */
+ private static final String VIEW_CREATE_COMPOSERS = "CREATE VIEW "+ MediaLibrary.VIEW_COMPOSERS+ " AS "
+ + "SELECT *, " + VIEW_COMPOSER_SELECT + " FROM "+MediaLibrary.TABLE_CONTRIBUTORS+" AS _composer WHERE "+MediaLibrary.ContributorColumns._ID+" IN "
+ +" (SELECT "+MediaLibrary.ContributorSongColumns._CONTRIBUTOR_ID+" FROM "+MediaLibrary.TABLE_CONTRIBUTORS_SONGS
+ +" WHERE "+MediaLibrary.ContributorSongColumns.ROLE+"="+MediaLibrary.ROLE_COMPOSER+" GROUP BY "+MediaLibrary.ContributorSongColumns._CONTRIBUTOR_ID+")"
+ +" ;";
+
/**
* View like VIEW_CREATE_ARTISTS but includes playlist information
*/
@@ -204,8 +257,11 @@ public class MediaSchema {
dbh.execSQL(INDEX_IDX_PLAYLIST_ID);
dbh.execSQL(INDEX_IDX_PLAYLIST_ID_SONG);
dbh.execSQL(VIEW_CREATE_SONGS_ALBUMS_ARTISTS);
+ dbh.execSQL(VIEW_CREATE_SONGS_ALBUMS_ARTISTS_HUGE);
dbh.execSQL(VIEW_CREATE_ALBUMS_ARTISTS);
dbh.execSQL(VIEW_CREATE_ARTISTS);
+ dbh.execSQL(VIEW_CREATE_ALBUMARTISTS);
+ dbh.execSQL(VIEW_CREATE_COMPOSERS);
dbh.execSQL(VIEW_CREATE_PLAYLIST_SONGS);
dbh.execSQL(DATABASE_CREATE_PREFERENCES);
}
@@ -240,6 +296,12 @@ public class MediaSchema {
dbh.execSQL("UPDATE songs SET mtime=1 WHERE mtime=0");
}
+ if (oldVersion < 20170217) {
+ dbh.execSQL(VIEW_CREATE_ALBUMARTISTS);
+ dbh.execSQL(VIEW_CREATE_COMPOSERS);
+ dbh.execSQL(VIEW_CREATE_SONGS_ALBUMS_ARTISTS_HUGE);
+ }
+
}
/**
diff --git a/src/ch/blinkenlights/android/vanilla/LibraryPagerAdapter.java b/src/ch/blinkenlights/android/vanilla/LibraryPagerAdapter.java
index e4d7907d..7aa5f80e 100644
--- a/src/ch/blinkenlights/android/vanilla/LibraryPagerAdapter.java
+++ b/src/ch/blinkenlights/android/vanilla/LibraryPagerAdapter.java
@@ -47,6 +47,7 @@ import android.widget.ListView;
import android.widget.TextView;
import android.widget.LinearLayout;
import java.util.Arrays;
+import java.util.ArrayList;
/**
* PagerAdapter that manages the library media ListViews.
@@ -62,18 +63,25 @@ public class LibraryPagerAdapter
* The number of unique list types. The number of visible lists may be
* smaller.
*/
- public static final int MAX_ADAPTER_COUNT = 6;
+ public static final int MAX_ADAPTER_COUNT = MediaUtils.TYPE_COUNT;
/**
* The human-readable title for each list. The positions correspond to the
* MediaUtils ids, so e.g. TITLES[MediaUtils.TYPE_SONG] = R.string.songs
*/
- public static final int[] TITLES = { R.string.artists, R.string.albums, R.string.songs,
- R.string.playlists, R.string.genres, R.string.files };
+ public static final int[] TITLES = { R.string.artists, R.string.albumartists, R.string.composers,
+ R.string.albums, R.string.songs, R.string.playlists,
+ R.string.genres, R.string.files };
/**
* Default tab order.
*/
- public static final int[] DEFAULT_ORDER = { MediaUtils.TYPE_ARTIST, MediaUtils.TYPE_ALBUM, MediaUtils.TYPE_SONG,
- MediaUtils.TYPE_PLAYLIST, MediaUtils.TYPE_GENRE, MediaUtils.TYPE_FILE };
+ public static final int[] DEFAULT_TAB_ORDER = { MediaUtils.TYPE_ARTIST, MediaUtils.TYPE_ALBARTIST, MediaUtils.TYPE_COMPOSER,
+ MediaUtils.TYPE_ALBUM, MediaUtils.TYPE_SONG, MediaUtils.TYPE_PLAYLIST,
+ MediaUtils.TYPE_GENRE, MediaUtils.TYPE_FILE };
+ /**
+ * The default visibility of tabs
+ */
+ public static final boolean[] DEFAULT_TAB_VISIBILITY = { true, false, false, true, true, true, true, true };
+
/**
* The user-chosen tab order.
*/
@@ -99,6 +107,14 @@ public class LibraryPagerAdapter
* The artist adapter instance, also stored at mAdapters[MediaUtils.TYPE_ARTIST].
*/
private MediaAdapter mArtistAdapter;
+ /**
+ * The albumartist adapter instance, also stored at mAdapters[MediaUtils.TYPE_ALBART].
+ */
+ private MediaAdapter mAlbArtAdapter;
+ /**
+ * The composer adapter instance, also stored at mAdapters[MediaUtils.TYPE_COMPOSER].
+ */
+ private MediaAdapter mComposerAdapter;
/**
* The album adapter instance, also stored at mAdapters[MediaUtils.TYPE_ALBUM].
*/
@@ -135,6 +151,14 @@ public class LibraryPagerAdapter
* A limiter that should be set when the album adapter is created.
*/
private Limiter mPendingArtistLimiter;
+ /**
+ * A limiter that should be set when the albumartist adapter is created.
+ */
+ private Limiter mPendingAlbArtLimiter;
+ /**
+ * A limiter that should be set when the composer adapter is created.
+ */
+ private Limiter mPendingComposerLimiter;
/**
* A limiter that should be set when the album adapter is created.
*/
@@ -165,9 +189,10 @@ public class LibraryPagerAdapter
* song limiters.
*/
private String mHeaderText;
- private DraggableRow mArtistHeader;
- private DraggableRow mAlbumHeader;
- private DraggableRow mSongHeader;
+ /**
+ * A list of header rows which require test updates
+ */
+ private ArrayList mHeaderViews = new ArrayList();
/**
* The current filter text, or null if none.
*/
@@ -224,23 +249,18 @@ public class LibraryPagerAdapter
public boolean loadTabOrder()
{
String in = PlaybackService.getSettings(mActivity).getString(PrefKeys.TAB_ORDER, PrefDefaults.TAB_ORDER);
- int[] order;
- int count;
- if (in == null || in.length() != MAX_ADAPTER_COUNT) {
- order = DEFAULT_ORDER;
- count = MAX_ADAPTER_COUNT;
- } else {
+ int[] order = new int[MAX_ADAPTER_COUNT];
+ int count = 0;
+ if (in != null && in.length() == MAX_ADAPTER_COUNT) {
char[] chars = in.toCharArray();
order = new int[MAX_ADAPTER_COUNT];
- count = 0;
for (int i = 0; i != MAX_ADAPTER_COUNT; ++i) {
char v = chars[i];
if (v >= 128) {
v -= 128;
if (v >= MediaUtils.TYPE_COUNT) {
- // invalid media type; use default order
- order = DEFAULT_ORDER;
- count = MAX_ADAPTER_COUNT;
+ // invalid media type, ignore all data
+ count = 0;
break;
}
order[count++] = v;
@@ -248,6 +268,14 @@ public class LibraryPagerAdapter
}
}
+ // set default tabs if none were loaded
+ if (count == 0) {
+ for (int i=0; i != MAX_ADAPTER_COUNT; i++) {
+ if (DEFAULT_TAB_VISIBILITY[i])
+ order[count++] = DEFAULT_TAB_ORDER[i];
+ }
+ }
+
if (count != mTabCount || !Arrays.equals(order, mTabOrder)) {
mTabOrder = order;
mTabCount = count;
@@ -316,18 +344,28 @@ public class LibraryPagerAdapter
case MediaUtils.TYPE_ARTIST:
adapter = mArtistAdapter = new MediaAdapter(activity, MediaUtils.TYPE_ARTIST, mPendingArtistLimiter, activity);
mArtistAdapter.setExpandable(mSongsPosition != -1 || mAlbumsPosition != -1);
- mArtistHeader = header = (DraggableRow)inflater.inflate(R.layout.draggable_row, null);
+ header = (DraggableRow)inflater.inflate(R.layout.draggable_row, null);
+ break;
+ case MediaUtils.TYPE_ALBARTIST:
+ adapter = mAlbArtAdapter = new MediaAdapter(activity, MediaUtils.TYPE_ALBARTIST, mPendingAlbArtLimiter, activity);
+ mAlbArtAdapter.setExpandable(mSongsPosition != -1 || mAlbumsPosition != -1);
+ header = (DraggableRow)inflater.inflate(R.layout.draggable_row, null);
+ break;
+ case MediaUtils.TYPE_COMPOSER:
+ adapter = mComposerAdapter = new MediaAdapter(activity, MediaUtils.TYPE_COMPOSER, mPendingComposerLimiter, activity);
+ mComposerAdapter.setExpandable(mSongsPosition != -1 || mAlbumsPosition != -1);
+ header = (DraggableRow)inflater.inflate(R.layout.draggable_row, null);
break;
case MediaUtils.TYPE_ALBUM:
adapter = mAlbumAdapter = new MediaAdapter(activity, MediaUtils.TYPE_ALBUM, mPendingAlbumLimiter, activity);
mAlbumAdapter.setExpandable(mSongsPosition != -1);
mPendingAlbumLimiter = null;
- mAlbumHeader = header = (DraggableRow)inflater.inflate(R.layout.draggable_row, null);
+ header = (DraggableRow)inflater.inflate(R.layout.draggable_row, null);
break;
case MediaUtils.TYPE_SONG:
adapter = mSongAdapter = new MediaAdapter(activity, MediaUtils.TYPE_SONG, mPendingSongLimiter, activity);
mPendingSongLimiter = null;
- mSongHeader = header = (DraggableRow)inflater.inflate(R.layout.draggable_row, null);
+ header = (DraggableRow)inflater.inflate(R.layout.draggable_row, null);
break;
case MediaUtils.TYPE_PLAYLIST:
adapter = mPlaylistAdapter = new MediaAdapter(activity, MediaUtils.TYPE_PLAYLIST, null, activity);
@@ -353,6 +391,7 @@ public class LibraryPagerAdapter
header.getTextView().setText(mHeaderText);
header.setTag(new ViewHolder()); // behave like a normal library row
view.addHeaderView(header);
+ mHeaderViews.add(header);
}
view.setAdapter(adapter);
if (type != MediaUtils.TYPE_FILE)
@@ -424,6 +463,8 @@ public class LibraryPagerAdapter
{
Bundle in = (Bundle)state;
mPendingArtistLimiter = (Limiter)in.getSerializable("limiter_artists");
+ mPendingAlbArtLimiter = (Limiter)in.getSerializable("limiter_albumartists");
+ mPendingComposerLimiter = (Limiter)in.getSerializable("limiter_composer");
mPendingAlbumLimiter = (Limiter)in.getSerializable("limiter_albums");
mPendingSongLimiter = (Limiter)in.getSerializable("limiter_songs");
mPendingFileLimiter = (Limiter)in.getSerializable("limiter_files");
@@ -435,6 +476,10 @@ public class LibraryPagerAdapter
Bundle out = new Bundle(10);
if (mArtistAdapter != null)
out.putSerializable("limiter_artists", mArtistAdapter.getLimiter());
+ if (mAlbArtAdapter != null)
+ out.putSerializable("limiter_albumartists", mAlbArtAdapter.getLimiter());
+ if (mComposerAdapter != null)
+ out.putSerializable("limiter_composer", mComposerAdapter.getLimiter());
if (mAlbumAdapter != null)
out.putSerializable("limiter_albums", mAlbumAdapter.getLimiter());
if (mSongAdapter != null)
@@ -452,12 +497,9 @@ public class LibraryPagerAdapter
*/
public void setHeaderText(String text)
{
- if (mArtistHeader != null)
- mArtistHeader.getTextView().setText(text);
- if (mAlbumHeader != null)
- mAlbumHeader.getTextView().setText(text);
- if (mSongHeader != null)
- mSongHeader.getTextView().setText(text);
+ for(DraggableRow row : mHeaderViews) {
+ row.getTextView().setText(text);
+ }
mHeaderText = text;
}
@@ -485,6 +527,20 @@ public class LibraryPagerAdapter
loadSortOrder(mArtistAdapter);
requestRequery(mArtistAdapter);
}
+ if (mAlbArtAdapter == null) {
+ mPendingAlbArtLimiter = null;
+ } else {
+ mAlbArtAdapter.setLimiter(null);
+ loadSortOrder(mAlbArtAdapter);
+ requestRequery(mAlbArtAdapter);
+ }
+ if (mComposerAdapter == null) {
+ mPendingComposerLimiter = null;
+ } else {
+ mComposerAdapter.setLimiter(null);
+ loadSortOrder(mComposerAdapter);
+ requestRequery(mComposerAdapter);
+ }
if (mAlbumAdapter == null) {
mPendingAlbumLimiter = null;
} else {
@@ -526,6 +582,8 @@ public class LibraryPagerAdapter
tab = mSongsPosition;
break;
case MediaUtils.TYPE_ARTIST:
+ case MediaUtils.TYPE_ALBARTIST:
+ case MediaUtils.TYPE_COMPOSER:
if (mAlbumAdapter == null) {
mPendingAlbumLimiter = limiter;
} else {
@@ -552,6 +610,20 @@ public class LibraryPagerAdapter
loadSortOrder(mArtistAdapter);
requestRequery(mArtistAdapter);
}
+ if (mAlbArtAdapter == null) {
+ mPendingAlbArtLimiter = limiter;
+ } else {
+ mAlbArtAdapter.setLimiter(limiter);
+ loadSortOrder(mAlbArtAdapter);
+ requestRequery(mAlbArtAdapter);
+ }
+ if (mComposerAdapter == null) {
+ mPendingComposerLimiter = limiter;
+ } else {
+ mComposerAdapter.setLimiter(limiter);
+ loadSortOrder(mComposerAdapter);
+ requestRequery(mComposerAdapter);
+ }
if (mAlbumAdapter == null) {
mPendingAlbumLimiter = limiter;
} else {
diff --git a/src/ch/blinkenlights/android/vanilla/MediaAdapter.java b/src/ch/blinkenlights/android/vanilla/MediaAdapter.java
index bcaaa68d..5a3be6d3 100644
--- a/src/ch/blinkenlights/android/vanilla/MediaAdapter.java
+++ b/src/ch/blinkenlights/android/vanilla/MediaAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015-2016 Adrian Ulrich
+ * Copyright (C) 2015-2017 Adrian Ulrich
* Copyright (C) 2010, 2011 Christopher Eby
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -189,6 +189,20 @@ public class MediaAdapter
mSortEntries = new int[] { R.string.title, R.string.date_added };
mAdapterSortValues = new String[] { MediaLibrary.ContributorColumns.ARTIST_SORT+" %1$s", MediaLibrary.ContributorColumns.MTIME+" %1$s" };
break;
+ case MediaUtils.TYPE_ALBARTIST:
+ mSource = MediaLibrary.VIEW_ALBUMARTISTS;
+ mFields = new String[] { MediaLibrary.ContributorColumns.ALBUMARTIST };
+ mFieldKeys = new String[] { MediaLibrary.ContributorColumns.ALBUMARTIST_SORT };
+ mSortEntries = new int[] { R.string.title, R.string.date_added };
+ mAdapterSortValues = new String[] { MediaLibrary.ContributorColumns.ALBUMARTIST_SORT+" %1$s", MediaLibrary.ContributorColumns.MTIME+" %1$s" };
+ break;
+ case MediaUtils.TYPE_COMPOSER:
+ mSource = MediaLibrary.VIEW_COMPOSERS;
+ mFields = new String[] { MediaLibrary.ContributorColumns.COMPOSER };
+ mFieldKeys = new String[] { MediaLibrary.ContributorColumns.COMPOSER_SORT };
+ mSortEntries = new int[] { R.string.title, R.string.date_added };
+ mAdapterSortValues = new String[] { MediaLibrary.ContributorColumns.COMPOSER_SORT+" %1$s", MediaLibrary.ContributorColumns.MTIME+" %1$s" };
+ break;
case MediaUtils.TYPE_ALBUM:
mSource = MediaLibrary.VIEW_ALBUMS_ARTISTS;
mFields = new String[] { MediaLibrary.AlbumColumns.ALBUM, MediaLibrary.ContributorColumns.ARTIST };
@@ -308,7 +322,7 @@ public class MediaAdapter
String sortRaw = mAdapterSortValues[mode];
if (returnSongs) {
// songs returned from the artist tab should also sort by album
- if (mType == MediaUtils.TYPE_ARTIST)
+ if (mType == MediaUtils.TYPE_ARTIST) // fixme: composer?
sortRaw += ", "+MediaLibrary.AlbumColumns.ALBUM_SORT+" %1$s";
// and this is for all types:
sortRaw += ", "+MediaLibrary.SongColumns.DISC_NUMBER+", "+MediaLibrary.SongColumns.SONG_NUMBER;
@@ -364,7 +378,7 @@ public class MediaAdapter
}
if (returnSongs == true) {
- source = MediaLibrary.VIEW_SONGS_ALBUMS_ARTISTS;
+ source = MediaLibrary.VIEW_SONGS_ALBUMS_ARTISTS_HUGE;
} else {
enrichedProjection = Arrays.copyOf(projection, projection.length + 1);
enrichedProjection[projection.length] = getFirstSortColumn();
@@ -443,6 +457,14 @@ public class MediaAdapter
fields = new String[] { cursor.getString(2) };
data = String.format("%s=%d", MediaLibrary.ContributorColumns.ARTIST_ID, id);
break;
+ case MediaUtils.TYPE_ALBARTIST:
+ fields = new String[] { cursor.getString(2) };
+ data = String.format("%s=%d", MediaLibrary.ContributorColumns.ALBUMARTIST_ID, id);
+ break;
+ case MediaUtils.TYPE_COMPOSER:
+ fields = new String[] { cursor.getString(2) };
+ data = String.format("%s=%d", MediaLibrary.ContributorColumns.COMPOSER_ID, id);
+ break;
case MediaUtils.TYPE_ALBUM:
fields = new String[] { cursor.getString(3), cursor.getString(2) };
data = String.format("%s=%d", MediaLibrary.SongColumns.ALBUM_ID, id);
diff --git a/src/ch/blinkenlights/android/vanilla/MediaUtils.java b/src/ch/blinkenlights/android/vanilla/MediaUtils.java
index 599b7d7a..c79e665f 100644
--- a/src/ch/blinkenlights/android/vanilla/MediaUtils.java
+++ b/src/ch/blinkenlights/android/vanilla/MediaUtils.java
@@ -62,31 +62,39 @@ public class MediaUtils {
* Type indicating an id represents an artist.
*/
public static final int TYPE_ARTIST = 0;
+ /**
+ * Type indicating an id represents an albumartist
+ */
+ public static final int TYPE_ALBARTIST = 1;
+ /**
+ * Type indicating an id represents a composer
+ */
+ public static final int TYPE_COMPOSER = 2;
/**
* Type indicating an id represents an album.
*/
- public static final int TYPE_ALBUM = 1;
+ public static final int TYPE_ALBUM = 3;
/**
* Type indicating an id represents a song.
*/
- public static final int TYPE_SONG = 2;
+ public static final int TYPE_SONG = 4;
/**
* Type indicating an id represents a playlist.
*/
- public static final int TYPE_PLAYLIST = 3;
+ public static final int TYPE_PLAYLIST = 5;
/**
* Type indicating ids represent genres.
*/
- public static final int TYPE_GENRE = 4;
+ public static final int TYPE_GENRE = 6;
/**
* Special type for files and folders. Most methods do not accept this type
* since files have no MediaStore id and require special handling.
*/
- public static final int TYPE_FILE = 5;
+ public static final int TYPE_FILE = 7;
/**
* The number of different valid media types.
*/
- public static final int TYPE_COUNT = 6;
+ public static final int TYPE_COUNT = 8;
/**
* The default sort order for media queries. First artist, then album, then
@@ -157,6 +165,12 @@ public class MediaUtils {
case TYPE_ARTIST:
selection.append(MediaLibrary.ContributorColumns.ARTIST_ID);
break;
+ case TYPE_ALBARTIST:
+ selection.append(MediaLibrary.ContributorColumns.ALBUMARTIST_ID);
+ break;
+ case TYPE_COMPOSER:
+ selection.append(MediaLibrary.ContributorColumns.COMPOSER_ID);
+ break;
case TYPE_ALBUM:
selection.append(MediaLibrary.SongColumns.ALBUM_ID);
sort = ALBUM_SORT;
@@ -206,6 +220,8 @@ public class MediaUtils {
{
switch (type) {
case TYPE_ARTIST:
+ case TYPE_ALBARTIST:
+ case TYPE_COMPOSER:
case TYPE_ALBUM:
case TYPE_SONG:
case TYPE_GENRE:
diff --git a/src/ch/blinkenlights/android/vanilla/TabOrderActivity.java b/src/ch/blinkenlights/android/vanilla/TabOrderActivity.java
index 702a850b..5a957cea 100644
--- a/src/ch/blinkenlights/android/vanilla/TabOrderActivity.java
+++ b/src/ch/blinkenlights/android/vanilla/TabOrderActivity.java
@@ -95,10 +95,10 @@ public class TabOrderActivity extends Activity
*/
public void restoreDefault()
{
- mAdapter.setTabIds(LibraryPagerAdapter.DEFAULT_ORDER.clone());
+ mAdapter.setTabIds(LibraryPagerAdapter.DEFAULT_TAB_ORDER.clone());
DragSortListView list = mList;
for (int i = 0; i != LibraryPagerAdapter.MAX_ADAPTER_COUNT; ++i) {
- list.setItemChecked(i, true);
+ list.setItemChecked(i, LibraryPagerAdapter.DEFAULT_TAB_VISIBILITY[i]);
}
save();
}