Add 'genres' page/function to Android Auto
This commit is contained in:
@@ -35,6 +35,7 @@ import com.cappielloantonio.tempo.subsonic.models.InternetRadioStation;
|
||||
import com.cappielloantonio.tempo.subsonic.models.MusicFolder;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Playlist;
|
||||
import com.cappielloantonio.tempo.subsonic.models.PodcastEpisode;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Genre;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.MappingUtil;
|
||||
import com.cappielloantonio.tempo.util.MusicUtil;
|
||||
@@ -952,6 +953,94 @@ public class AutomotiveRepository {
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getGenres(String prefix) {
|
||||
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
|
||||
|
||||
App.getSubsonicClientInstance(false)
|
||||
.getBrowsingClient()
|
||||
.getGenres()
|
||||
.enqueue(new Callback<ApiResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
||||
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getGenres() != null && response.body().getSubsonicResponse().getGenres().getGenres() != null) {
|
||||
List<Genre> genres = response.body().getSubsonicResponse().getGenres().getGenres();
|
||||
|
||||
// Sort genres alphabetically by name
|
||||
genres.sort((g1, g2) -> {
|
||||
String name1 = g1.getGenre() != null ? g1.getGenre() : "";
|
||||
String name2 = g2.getGenre() != null ? g2.getGenre() : "";
|
||||
return name1.compareToIgnoreCase(name2);
|
||||
});
|
||||
|
||||
List<MediaItem> mediaItems = new ArrayList<>();
|
||||
|
||||
for (Genre genre : genres) {
|
||||
MediaMetadata mediaMetadata = new MediaMetadata.Builder()
|
||||
.setTitle(genre.getGenre())
|
||||
.setIsBrowsable(true)
|
||||
.setIsPlayable(false)
|
||||
.setMediaType(MediaMetadata.MEDIA_TYPE_PLAYLIST)
|
||||
.build();
|
||||
|
||||
MediaItem mediaItem = new MediaItem.Builder()
|
||||
.setMediaId(prefix + genre.getGenre())
|
||||
.setMediaMetadata(mediaMetadata)
|
||||
.setUri("")
|
||||
.build();
|
||||
|
||||
mediaItems.add(mediaItem);
|
||||
}
|
||||
|
||||
LibraryResult<ImmutableList<MediaItem>> libraryResult = LibraryResult.ofItemList(ImmutableList.copyOf(mediaItems), null);
|
||||
|
||||
listenableFuture.set(libraryResult);
|
||||
} else {
|
||||
listenableFuture.set(LibraryResult.ofError(LibraryResult.RESULT_ERROR_BAD_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
|
||||
listenableFuture.setException(t);
|
||||
}
|
||||
});
|
||||
|
||||
return listenableFuture;
|
||||
}
|
||||
|
||||
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getSongsByGenre(String genre, int count) {
|
||||
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
|
||||
|
||||
App.getSubsonicClientInstance(false)
|
||||
.getAlbumSongListClient()
|
||||
.getSongsByGenre(genre, count, 0)
|
||||
.enqueue(new Callback<ApiResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
||||
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getSongsByGenre() != null && response.body().getSubsonicResponse().getSongsByGenre().getSongs() != null) {
|
||||
List<com.cappielloantonio.tempo.subsonic.models.Child> songs = response.body().getSubsonicResponse().getSongsByGenre().getSongs();
|
||||
|
||||
setChildrenMetadata(songs);
|
||||
|
||||
List<MediaItem> mediaItems = MappingUtil.mapMediaItems(songs);
|
||||
|
||||
LibraryResult<ImmutableList<MediaItem>> libraryResult = LibraryResult.ofItemList(ImmutableList.copyOf(mediaItems), null);
|
||||
|
||||
listenableFuture.set(libraryResult);
|
||||
} else {
|
||||
listenableFuture.set(LibraryResult.ofError(LibraryResult.RESULT_ERROR_BAD_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
|
||||
listenableFuture.setException(t);
|
||||
}
|
||||
});
|
||||
|
||||
return listenableFuture;
|
||||
}
|
||||
|
||||
private static class GetMediaItemThreadSafe implements Runnable {
|
||||
private final SessionMediaItemDao sessionMediaItemDao;
|
||||
private final String id;
|
||||
|
||||
11
app/src/main/res/drawable/ic_aa_genres.xml
Normal file
11
app/src/main/res/drawable/ic_aa_genres.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="960"
|
||||
android:viewportWidth="960"
|
||||
android:width="24dp">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M480,660Q555,660 607.5,607.5Q660,555 660,480Q660,405 607.5,352.5Q555,300 480,300Q405,300 352.5,352.5Q300,405 300,480Q300,555 352.5,607.5Q405,660 480,660ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880Z"/>
|
||||
|
||||
</vector>
|
||||
@@ -310,8 +310,9 @@
|
||||
<!-- <item>For you</item> -->
|
||||
<item>Star tracks</item>
|
||||
<item>Star albums</item>
|
||||
<item>Star artistes</item>
|
||||
<item>Star artists</item>
|
||||
<item>Random</item>
|
||||
<item>Genres</item>
|
||||
</string-array>
|
||||
<string-array name="aa_tab_values">
|
||||
<item>-1</item>
|
||||
@@ -331,6 +332,7 @@
|
||||
<item>13</item>
|
||||
<item>14</item>
|
||||
<item>15</item>
|
||||
<item>16</item>
|
||||
</string-array>
|
||||
<!-- end Add by MFO -->
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<string name="aa_podcast">Podcast</string>
|
||||
<string name="aa_radio">Radio</string>
|
||||
<string name="aa_random">Random</string>
|
||||
<string name="aa_genres">Genres</string>
|
||||
<string name="aa_recent_albums">Recent</string>
|
||||
<string name="aa_song_recently_played">Song played</string>
|
||||
<string name="aa_starred_albums">★ Albums</string>
|
||||
|
||||
@@ -50,6 +50,7 @@ object MediaBrowserTree {
|
||||
private const val STARRED_ARTISTS_ID = "[starredArtistsID]"
|
||||
private const val RANDOM_ID = "[randomID]"
|
||||
private const val FOLDER_ID = "[folderID]"
|
||||
private const val GENRES_ID = "[genresID]"
|
||||
|
||||
// System functions
|
||||
private const val INDEX_ID = "[indexID]"
|
||||
@@ -178,7 +179,8 @@ object MediaBrowserTree {
|
||||
STARRED_TRACKS_ID,
|
||||
STARRED_ALBUMS_ID,
|
||||
STARRED_ARTISTS_ID,
|
||||
RANDOM_ID
|
||||
RANDOM_ID,
|
||||
GENRES_ID
|
||||
)
|
||||
|
||||
// Root level
|
||||
@@ -419,6 +421,19 @@ object MediaBrowserTree {
|
||||
)
|
||||
)
|
||||
|
||||
treeNodes[GENRES_ID] =
|
||||
MediaItemNode(
|
||||
buildMediaItem(
|
||||
gridView = albumView,
|
||||
title = appContext.getString(R.string.aa_genres),
|
||||
mediaId = GENRES_ID,
|
||||
isPlayable = false,
|
||||
isBrowsable = true,
|
||||
imageUri = iconUri(R.drawable.ic_aa_genres),
|
||||
mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_MIXED
|
||||
)
|
||||
)
|
||||
|
||||
val root = treeNodes[ROOT_ID]!!
|
||||
val selectedIds = mutableSetOf<String>()
|
||||
|
||||
@@ -474,6 +489,7 @@ object MediaBrowserTree {
|
||||
STARRED_ALBUMS_ID -> automotiveRepository.getStarredAlbums(id)
|
||||
STARRED_ARTISTS_ID -> automotiveRepository.getStarredArtists(id)
|
||||
RANDOM_ID -> automotiveRepository.getRandomSongs(100)
|
||||
GENRES_ID -> automotiveRepository.getGenres(id)
|
||||
|
||||
else -> {
|
||||
if (id.startsWith(LAST_PLAYED_ID)) {
|
||||
@@ -512,6 +528,10 @@ object MediaBrowserTree {
|
||||
return automotiveRepository.getArtistAlbum(STARRED_ALBUMS_ID,id.removePrefix(STARRED_ARTISTS_ID))
|
||||
}
|
||||
|
||||
if (id.startsWith(GENRES_ID)) {
|
||||
return automotiveRepository.getSongsByGenre(id.removePrefix(GENRES_ID), 100)
|
||||
}
|
||||
|
||||
if (id.startsWith(PLAYLIST_ID)) {
|
||||
return automotiveRepository.getPlaylistSongs(id.removePrefix(PLAYLIST_ID))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user