Remove unknown genre, add number of songs
This commit is contained in:
parent
b0c98e7787
commit
918090ee63
6 changed files with 52 additions and 74 deletions
|
|
@ -59,6 +59,9 @@ public class GenreAdapter extends RecyclerView.Adapter<GenreAdapter.ViewHolder>
|
||||||
if (holder.title != null) {
|
if (holder.title != null) {
|
||||||
holder.title.setText(genre.name);
|
holder.title.setText(genre.name);
|
||||||
}
|
}
|
||||||
|
if (holder.text != null) {
|
||||||
|
holder.text.setText(MusicUtil.getGenreInfoString(activity, genre));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,10 @@ package com.kabouzeid.gramophone.loader;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
|
||||||
import android.provider.BaseColumns;
|
|
||||||
import android.provider.MediaStore.Audio.Genres;
|
import android.provider.MediaStore.Audio.Genres;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import com.kabouzeid.gramophone.R;
|
|
||||||
import com.kabouzeid.gramophone.model.Genre;
|
import com.kabouzeid.gramophone.model.Genre;
|
||||||
import com.kabouzeid.gramophone.model.Song;
|
import com.kabouzeid.gramophone.model.Song;
|
||||||
import com.kabouzeid.gramophone.util.PreferenceUtil;
|
import com.kabouzeid.gramophone.util.PreferenceUtil;
|
||||||
|
|
@ -23,26 +20,16 @@ public class GenreLoader {
|
||||||
Genres._ID,
|
Genres._ID,
|
||||||
Genres.NAME
|
Genres.NAME
|
||||||
};
|
};
|
||||||
// Genres that actually have songs
|
|
||||||
final String selection = Genres._ID + " IN" +
|
|
||||||
" (SELECT " + Genres.Members.GENRE_ID + " FROM audio_genres_map WHERE " + Genres.Members.AUDIO_ID + " IN" +
|
|
||||||
" (SELECT " + Genres._ID + " FROM audio_meta WHERE " + SongLoader.BASE_SELECTION + "))";
|
|
||||||
|
|
||||||
final Cursor cursor = context.getContentResolver().query(
|
final Cursor cursor = context.getContentResolver().query(
|
||||||
Genres.EXTERNAL_CONTENT_URI,
|
Genres.EXTERNAL_CONTENT_URI,
|
||||||
projection, selection, null, PreferenceUtil.getInstance(context).getGenreSortOrder());
|
projection, null, null, PreferenceUtil.getInstance(context).getGenreSortOrder());
|
||||||
|
|
||||||
return getGenresFromCursor(context, cursor);
|
return getGenresFromCursor(context, cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static ArrayList<Song> getSongs(@NonNull final Context context, final int genreId) {
|
public static ArrayList<Song> getSongs(@NonNull final Context context, final int genreId) {
|
||||||
// The genres table only stores songs that have a genre specified,
|
|
||||||
// so we need to get songs without a genre a different way.
|
|
||||||
if (genreId == -1) {
|
|
||||||
return getSongsWithNoGenre(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Cursor cursor = context.getContentResolver().query(
|
final Cursor cursor = context.getContentResolver().query(
|
||||||
Genres.Members.getContentUri("external", genreId),
|
Genres.Members.getContentUri("external", genreId),
|
||||||
SongLoader.BASE_PROJECTION, SongLoader.BASE_SELECTION, null, null);
|
SongLoader.BASE_PROJECTION, SongLoader.BASE_SELECTION, null, null);
|
||||||
|
|
@ -53,15 +40,10 @@ public class GenreLoader {
|
||||||
@NonNull
|
@NonNull
|
||||||
private static ArrayList<Genre> getGenresFromCursor(@NonNull final Context context, @Nullable final Cursor cursor) {
|
private static ArrayList<Genre> getGenresFromCursor(@NonNull final Context context, @Nullable final Cursor cursor) {
|
||||||
final ArrayList<Genre> genres = new ArrayList<>();
|
final ArrayList<Genre> genres = new ArrayList<>();
|
||||||
|
|
||||||
if (hasSongsWithNoGenre(context)) {
|
|
||||||
genres.add(new Genre(context.getResources().getString(R.string.unknown_genre)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cursor != null) {
|
if (cursor != null) {
|
||||||
if (cursor.moveToFirst()) {
|
if (cursor.moveToFirst()) {
|
||||||
do {
|
do {
|
||||||
genres.add(getGenreFromCursor(cursor));
|
genres.add(getGenreFromCursor(context, cursor));
|
||||||
} while (cursor.moveToNext());
|
} while (cursor.moveToNext());
|
||||||
}
|
}
|
||||||
cursor.close();
|
cursor.close();
|
||||||
|
|
@ -70,41 +52,10 @@ public class GenreLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private static Genre getGenreFromCursor(@NonNull final Cursor cursor) {
|
private static Genre getGenreFromCursor(@NonNull final Context context, @NonNull final Cursor cursor) {
|
||||||
final int id = cursor.getInt(0);
|
final int id = cursor.getInt(0);
|
||||||
final String name = cursor.getString(1);
|
final String name = cursor.getString(1);
|
||||||
return new Genre(id, name);
|
final int songs = getSongs(context, id).size();
|
||||||
}
|
return new Genre(id, name, songs);
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private static ArrayList<Song> getSongsWithNoGenre(@NonNull final Context context) {
|
|
||||||
String selection = BaseColumns._ID + " NOT IN " +
|
|
||||||
"(SELECT " + Genres.Members.AUDIO_ID + " FROM audio_genres_map)";
|
|
||||||
return SongLoader.getSongs(SongLoader.makeSongCursor(context, selection, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean hasSongsWithNoGenre(@NonNull final Context context) {
|
|
||||||
final Cursor allSongsCursor = SongLoader.makeSongCursor(context, null, null);
|
|
||||||
final Cursor allSongsWithGenreCursor = makeAllSongsWithGenreCursor(context);
|
|
||||||
|
|
||||||
if (allSongsCursor == null || allSongsWithGenreCursor == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean hasSongsWithNoGenre = allSongsCursor.getCount() > allSongsWithGenreCursor.getCount();
|
|
||||||
allSongsCursor.close();
|
|
||||||
allSongsWithGenreCursor.close();
|
|
||||||
return hasSongsWithNoGenre;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static Cursor makeAllSongsWithGenreCursor(@NonNull final Context context) {
|
|
||||||
try {
|
|
||||||
return context.getContentResolver().query(
|
|
||||||
Uri.parse("content://media/external/audio/genres/all/members"),
|
|
||||||
new String[]{Genres.Members.AUDIO_ID}, null, null, null);
|
|
||||||
} catch (SecurityException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,12 @@ import android.os.Parcelable;
|
||||||
public class Genre implements Parcelable {
|
public class Genre implements Parcelable {
|
||||||
public final int id;
|
public final int id;
|
||||||
public final String name;
|
public final String name;
|
||||||
|
public final int songs;
|
||||||
|
|
||||||
public Genre(final int id, final String name) {
|
public Genre(final int id, final String name, final int songs) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
this.songs = songs;
|
||||||
|
|
||||||
// For unknown genre
|
|
||||||
public Genre(final String name) {
|
|
||||||
this.id = -1;
|
|
||||||
this.name = name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -26,13 +22,15 @@ public class Genre implements Parcelable {
|
||||||
Genre genre = (Genre) o;
|
Genre genre = (Genre) o;
|
||||||
|
|
||||||
if (id != genre.id) return false;
|
if (id != genre.id) return false;
|
||||||
return name != null ? name.equals(genre.name) : genre.name == null;
|
if (!name.equals(genre.name)) return false;
|
||||||
|
return songs == genre.songs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = id;
|
int result = id;
|
||||||
result = 31 * result + (name != null ? name.hashCode() : 0);
|
result = 31 * result + name.hashCode();
|
||||||
|
result = 31 * result + songs;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,6 +39,7 @@ public class Genre implements Parcelable {
|
||||||
return "Genre{" +
|
return "Genre{" +
|
||||||
"id=" + id +
|
"id=" + id +
|
||||||
", name='" + name + '\'' +
|
", name='" + name + '\'' +
|
||||||
|
", songs=" + songs +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,11 +52,13 @@ public class Genre implements Parcelable {
|
||||||
public void writeToParcel(Parcel dest, int flags) {
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
dest.writeInt(this.id);
|
dest.writeInt(this.id);
|
||||||
dest.writeString(this.name);
|
dest.writeString(this.name);
|
||||||
|
dest.writeInt(this.songs);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Genre(Parcel in) {
|
protected Genre(Parcel in) {
|
||||||
this.id = in.readInt();
|
this.id = in.readInt();
|
||||||
this.name = in.readString();
|
this.name = in.readString();
|
||||||
|
this.songs = in.readInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Creator<Genre> CREATOR = new Creator<Genre>() {
|
public static final Creator<Genre> CREATOR = new Creator<Genre>() {
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
|
||||||
import com.kabouzeid.gramophone.loader.PlaylistLoader;
|
import com.kabouzeid.gramophone.loader.PlaylistLoader;
|
||||||
import com.kabouzeid.gramophone.loader.SongLoader;
|
import com.kabouzeid.gramophone.loader.SongLoader;
|
||||||
import com.kabouzeid.gramophone.model.Artist;
|
import com.kabouzeid.gramophone.model.Artist;
|
||||||
|
import com.kabouzeid.gramophone.model.Genre;
|
||||||
import com.kabouzeid.gramophone.model.Playlist;
|
import com.kabouzeid.gramophone.model.Playlist;
|
||||||
import com.kabouzeid.gramophone.model.Song;
|
import com.kabouzeid.gramophone.model.Song;
|
||||||
import com.kabouzeid.gramophone.model.lyrics.AbsSynchronizedLyrics;
|
import com.kabouzeid.gramophone.model.lyrics.AbsSynchronizedLyrics;
|
||||||
|
|
@ -114,6 +115,13 @@ public class MusicUtil {
|
||||||
return albumCount + " " + albumString + " • " + songCount + " " + songString;
|
return albumCount + " " + albumString + " • " + songCount + " " + songString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static String getGenreInfoString(@NonNull final Context context, @NonNull final Genre genre) {
|
||||||
|
int songCount = genre.songs;
|
||||||
|
String songString = songCount == 1 ? context.getResources().getString(R.string.song) : context.getResources().getString(R.string.songs);
|
||||||
|
return songCount + " " + songString;
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static String getPlaylistInfoString(@NonNull final Context context, @NonNull List<Song> songs) {
|
public static String getPlaylistInfoString(@NonNull final Context context, @NonNull List<Song> songs) {
|
||||||
final int songCount = songs.size();
|
final int songCount = songs.size();
|
||||||
|
|
|
||||||
|
|
@ -6,18 +6,34 @@
|
||||||
android:foreground="?attr/rectSelector"
|
android:foreground="?attr/rectSelector"
|
||||||
tools:ignore="UnusedAttribute">
|
tools:ignore="UnusedAttribute">
|
||||||
|
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/title"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:layout_marginEnd="16dp"
|
android:paddingEnd="16dp"
|
||||||
android:layout_marginLeft="16dp"
|
android:paddingLeft="16dp"
|
||||||
android:layout_marginRight="16dp"
|
android:paddingRight="16dp"
|
||||||
android:layout_marginStart="16dp"
|
android:paddingStart="16dp"
|
||||||
android:fontFamily="sans-serif"
|
android:orientation="vertical">
|
||||||
android:singleLine="true"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="sans-serif"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="sans-serif"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
android:textColor="?android:textColorSecondary" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/separator"
|
android:id="@+id/separator"
|
||||||
|
|
@ -26,4 +42,4 @@
|
||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
android:background="?attr/dividerColor" />
|
android:background="?attr/dividerColor" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,6 @@
|
||||||
<string name="album">Album</string>
|
<string name="album">Album</string>
|
||||||
<string name="artist">Artist</string>
|
<string name="artist">Artist</string>
|
||||||
<string name="genre">Genre</string>
|
<string name="genre">Genre</string>
|
||||||
<string name="unknown_genre">Unknown genre</string>
|
|
||||||
<string name="album_artist">Album artist</string>
|
<string name="album_artist">Album artist</string>
|
||||||
<string name="year">Year</string>
|
<string name="year">Year</string>
|
||||||
<string name="track_hint">"Track (2 for track 2 or 3004 for CD3 track 4)"</string>
|
<string name="track_hint">"Track (2 for track 2 or 3004 for CD3 track 4)"</string>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue