diff --git a/app/src/main/java/com/cappielloantonio/tempo/repository/AutomotiveRepository.java b/app/src/main/java/com/cappielloantonio/tempo/repository/AutomotiveRepository.java index 8fd49fc7..86b6fa38 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/repository/AutomotiveRepository.java +++ b/app/src/main/java/com/cappielloantonio/tempo/repository/AutomotiveRepository.java @@ -1,6 +1,5 @@ package com.cappielloantonio.tempo.repository; - import android.content.ContentResolver; import android.net.Uri; import android.view.View; @@ -69,6 +68,16 @@ public class AutomotiveRepository { if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getAlbumList2() != null && response.body().getSubsonicResponse().getAlbumList2().getAlbums() != null) { List albums = response.body().getSubsonicResponse().getAlbumList2().getAlbums(); + // add by MFO + // Hack for artist view + if("alphabeticalByArtist".equals(type))for(AlbumID3 album : albums){ + String artistName = album.getArtist(); + String albumName = album.getName(); + album.setName(artistName); + album.setArtist(albumName); + } + // end add by MFO + List mediaItems = new ArrayList<>(); for (AlbumID3 album : albums) { diff --git a/app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt b/app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt index 47c30cc0..c72f767f 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt +++ b/app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt @@ -90,8 +90,17 @@ object Preferences { private const val ARTIST_DISPLAY_BIOGRAPHY= "artist_display_biography" private const val NETWORK_PING_TIMEOUT = "network_ping_timeout_base" - - @JvmStatic + private const val AA_ALBUM_VIEW = "androidauto_album_view" + private const val AA_HOME_VIEW = "androidauto_home_view" + private const val AA_PLAYLIST_VIEW = "androidauto_playlist_view" + private const val AA_PODCAST_VIEW = "androidauto_podcast_view" + private const val AA_RADIO_VIEW = "androidauto_radio_view" + private const val AA_FIRST_TAB = "androidauto_first_tab" + private const val AA_SECOND_TAB = "androidauto_second_tab" + private const val AA_THIRD_TAB = "androidauto_third_tab" + private const val AA_FOURTH_TAB = "androidauto_fourth_tab" + + @JvmStatic fun getServer(): String? { return App.getInstance().preferences.getString(SERVER, null) } @@ -736,4 +745,50 @@ object Preferences { fun setArtistDisplayBiography(displayBiographyEnabled: Boolean) { App.getInstance().preferences.edit().putBoolean(ARTIST_DISPLAY_BIOGRAPHY, displayBiographyEnabled).apply() } + + @JvmStatic + fun isAndroidAutoAlbumViewEnabled(): Boolean { + return App.getInstance().preferences.getBoolean(AA_ALBUM_VIEW, true) + } + + @JvmStatic + fun isAndroidAutoHomeViewEnabled(): Boolean { + return App.getInstance().preferences.getBoolean(AA_HOME_VIEW, false) + } + + @JvmStatic + fun isAndroidAutoPlaylistViewEnabled(): Boolean { + return App.getInstance().preferences.getBoolean(AA_PLAYLIST_VIEW, false) + } + + @JvmStatic + fun isAndroidAutoPodcastViewEnabled(): Boolean { + return App.getInstance().preferences.getBoolean(AA_PODCAST_VIEW, false) + } + + @JvmStatic + fun isAndroidAutoRadioViewEnabled(): Boolean { + return App.getInstance().preferences.getBoolean(AA_RADIO_VIEW, false) + } + + @JvmStatic + fun getAndroidAutoFirstTab(): Int { + return App.getInstance().preferences.getString(AA_FIRST_TAB, "0")!!.toInt() + } + + @JvmStatic + fun getAndroidAutoSecondTab(): Int { + return App.getInstance().preferences.getString(AA_SECOND_TAB, "1")!!.toInt() + } + + @JvmStatic + fun getAndroidAutoThirdTab(): Int { + return App.getInstance().preferences.getString(AA_THIRD_TAB, "2")!!.toInt() + } + + @JvmStatic + fun getAndroidAutoFourthTab(): Int { + return App.getInstance().preferences.getString(AA_FOURTH_TAB, "3")!!.toInt() + } + } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_aa_added_album.xml b/app/src/main/res/drawable/ic_aa_added_album.xml new file mode 100644 index 00000000..061627c4 --- /dev/null +++ b/app/src/main/res/drawable/ic_aa_added_album.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_aa_added_title.xml b/app/src/main/res/drawable/ic_aa_added_title.xml new file mode 100644 index 00000000..5c42a736 --- /dev/null +++ b/app/src/main/res/drawable/ic_aa_added_title.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_aa_albums.xml b/app/src/main/res/drawable/ic_aa_albums.xml new file mode 100644 index 00000000..02c2338d --- /dev/null +++ b/app/src/main/res/drawable/ic_aa_albums.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_aa_artists.xml b/app/src/main/res/drawable/ic_aa_artists.xml new file mode 100644 index 00000000..b1003873 --- /dev/null +++ b/app/src/main/res/drawable/ic_aa_artists.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_aa_folders.xml b/app/src/main/res/drawable/ic_aa_folders.xml new file mode 100644 index 00000000..3fe8267a --- /dev/null +++ b/app/src/main/res/drawable/ic_aa_folders.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_aa_for_you.xml b/app/src/main/res/drawable/ic_aa_for_you.xml new file mode 100644 index 00000000..437c89d2 --- /dev/null +++ b/app/src/main/res/drawable/ic_aa_for_you.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_aa_home.xml b/app/src/main/res/drawable/ic_aa_home.xml new file mode 100644 index 00000000..2b3bead9 --- /dev/null +++ b/app/src/main/res/drawable/ic_aa_home.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_aa_mostplayed.xml b/app/src/main/res/drawable/ic_aa_mostplayed.xml new file mode 100644 index 00000000..35480ea3 --- /dev/null +++ b/app/src/main/res/drawable/ic_aa_mostplayed.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_aa_other.xml b/app/src/main/res/drawable/ic_aa_other.xml new file mode 100644 index 00000000..b0b0324e --- /dev/null +++ b/app/src/main/res/drawable/ic_aa_other.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_aa_playlist.xml b/app/src/main/res/drawable/ic_aa_playlist.xml new file mode 100644 index 00000000..fd7c3346 --- /dev/null +++ b/app/src/main/res/drawable/ic_aa_playlist.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_aa_podcasts.xml b/app/src/main/res/drawable/ic_aa_podcasts.xml new file mode 100644 index 00000000..8de5115b --- /dev/null +++ b/app/src/main/res/drawable/ic_aa_podcasts.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_aa_radio.xml b/app/src/main/res/drawable/ic_aa_radio.xml new file mode 100644 index 00000000..bb5b767c --- /dev/null +++ b/app/src/main/res/drawable/ic_aa_radio.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_aa_random.xml b/app/src/main/res/drawable/ic_aa_random.xml new file mode 100644 index 00000000..c101ceb5 --- /dev/null +++ b/app/src/main/res/drawable/ic_aa_random.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_aa_recent.xml b/app/src/main/res/drawable/ic_aa_recent.xml new file mode 100644 index 00000000..ab5c428a --- /dev/null +++ b/app/src/main/res/drawable/ic_aa_recent.xml @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_aa_recent_title.xml b/app/src/main/res/drawable/ic_aa_recent_title.xml new file mode 100644 index 00000000..92e816d6 --- /dev/null +++ b/app/src/main/res/drawable/ic_aa_recent_title.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_aa_star_album.xml b/app/src/main/res/drawable/ic_aa_star_album.xml new file mode 100644 index 00000000..dfb801a0 --- /dev/null +++ b/app/src/main/res/drawable/ic_aa_star_album.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_aa_star_title.xml b/app/src/main/res/drawable/ic_aa_star_title.xml new file mode 100644 index 00000000..db0264a1 --- /dev/null +++ b/app/src/main/res/drawable/ic_aa_star_title.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values-fr/arrays.xml b/app/src/main/res/values-fr/arrays.xml index 7d0198c0..3d488f65 100644 --- a/app/src/main/res/values-fr/arrays.xml +++ b/app/src/main/res/values-fr/arrays.xml @@ -254,4 +254,46 @@ 3 4 + + + + Ne pas afficher + Accueil + Récent + Albums + Artists + Playlists + Podcast + Radio + Dossiers + Albums plus joués + + Albums ajouté + + Titres favoris + Albums favoris + Artistes favoris + Aléatoire + + + -1 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + + + diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 7015e90c..49eb4222 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -1,4 +1,22 @@ + Albums + Albums plus joués + Albums ajoutés + Artistes + Accueil + Pour vous + Plus + Dossiers + Playlists + Podcast + Radio + Aléatoire + Récents + Titres joués + ★ Albums + ★ Artistes + ★ Titres + Si vous rencontrez un problème, visitez https://dontkillmyapp.com. Des instructions pour désactiver les fonctions de sauvegarde d\'énergie qui pourrait affecter les performance de l\'app y sont disponibles. Veuillez désactiver les optimisations de la batterie pour permettre la lecture des médias lorsque l\'écran est éteint. Optimisations de la batterie @@ -310,6 +328,16 @@ Toujours visible Autoriser l\'ajout de doublons à une playlist Si activé, les doublons ne seront pas détectés à l\'ajout d\'un titre à une playlist. + Android Auto + Vue en grille des albums + Vue en grille du menu accueil + Vue en grille des playlists + Vue en grille des podcasts + Vue en grille des radios + Affichage du premier onglet + Affichage du deuxième onglet + Affichage du troisième onglet + Affichage du quatrième onglet Format de transcodage Si activé, Tempus ne forcera pas le téléchargement de la piste avec les paramètres de transcodage ci-dessous. Prioriser les paramètres du serveurs, utilisés pour le streaming, dans les téléchargements @@ -404,7 +432,7 @@ Si activé, les pistes favorites seront téléchargées pour l\'écoute hors-ligne. Synchronisation des pistes favorites pour écoute hors-ligne Thème - Données + Données Géneral Playlist Note @@ -463,7 +491,7 @@ Téléchargé Titres les plus joués Titres ajoutés récemment - Titrés joués récemment + Titres joués récemment Titres favoris Les meilleurs titres de %1$s Année %1$d diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 49aef94e..b9c6587b 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -278,4 +278,46 @@ 6 7 + + + + Do not display + Home + Recent + Albums + Artists + Playlists + Podcast + Radio + Folder + Albums most played + + Albums added + + Star tracks + Star albums + Star artistes + Random + + + -1 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d6d2b2ca..37558c33 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,4 +1,22 @@ + Albums + Albums most played + Albums added + Artists + Home + For you + More + Folder + Playlists + Podcast + Radio + Random + Recent + Song played + ★ Albums + ★ Artists + ★ Tracks + If in trouble visit https://dontkillmyapp.com. It provides detailed instructions on how to disable any power-saving features that may affect app\'s performance. Please disable battery optimizations for media playback while the screen is off. Battery Optimizations @@ -373,6 +391,16 @@ Show podcast If enabled, show the podcast section. Restart the app for it to take full effect. Playlist sorting + Android Auto + Grid view for albums + Grid view for home + Grid view for playlists + Grid view for podcast + Grid view for radio + First tab display + Second tab display + Third tab display + Fourth tab display Show audio quality The bitrate and audio format will be shown for each audio track. Show song star rating diff --git a/app/src/main/res/xml/global_preferences.xml b/app/src/main/res/xml/global_preferences.xml index cdb875a9..02a47086 100644 --- a/app/src/main/res/xml/global_preferences.xml +++ b/app/src/main/res/xml/global_preferences.xml @@ -146,7 +146,7 @@ android:defaultValue="false" android:summary="@string/search_sort_summary" android:key="sort_search_chronologically" /> - + - + @@ -454,6 +454,76 @@ android:key="github_update_check" /> + + + + + + + + + + + + + + + + + + + + + + + + + = mutableMapOf() private var isInitialized = false +/* data class FunctionItem( + val id: String, + var isDisplayed: Boolean + ) +*/ // Root private const val ROOT_ID = "[rootID]" - - // First level + // Available functions private const val HOME_ID = "[homeID]" - private const val LIBRARY_ID = "[libraryID]" - private const val OTHER_ID = "[otherID]" - - // Second level HOME_ID - private const val MOST_PLAYED_ID = "[mostPlayedID]" private const val LAST_PLAYED_ID = "[lastPlayedID]" + private const val ALBUMS_ID = "[albumsID]" + private const val ARTISTS_ID = "[artistsID]" + private const val MOST_PLAYED_ID = "[mostPlayedID]" + private const val PLAYLIST_ID = "[playlistID]" + private const val PODCAST_ID = "[podcastID]" + private const val RADIO_ID = "[radioID]" private const val RECENTLY_ADDED_ID = "[recentlyAddedID]" private const val RECENT_SONGS_ID = "[recentSongsID]" private const val MADE_FOR_YOU_ID = "[madeForYouID]" @@ -39,20 +49,17 @@ object MediaBrowserTree { private const val STARRED_ALBUMS_ID = "[starredAlbumsID]" private const val STARRED_ARTISTS_ID = "[starredArtistsID]" private const val RANDOM_ID = "[randomID]" - - // Second level LIBRARY_ID private const val FOLDER_ID = "[folderID]" + + // System functions private const val INDEX_ID = "[indexID]" private const val DIRECTORY_ID = "[directoryID]" - private const val PLAYLIST_ID = "[playlistID]" - - // Second level OTHER_ID - private const val PODCAST_ID = "[podcastID]" - private const val RADIO_ID = "[radioID]" - private const val ALBUM_ID = "[albumID]" private const val ARTIST_ID = "[artistID]" + private fun iconUri(resId: Int): Uri = + Uri.parse("android.resource://${BuildConfig.APPLICATION_ID}/$resId") + private class MediaItemNode(val item: MediaItem) { private val children: MutableList = ArrayList() @@ -71,6 +78,7 @@ object MediaBrowserTree { } private fun buildMediaItem( + gridView: Boolean, title: String, mediaId: String, isPlayable: Boolean, @@ -83,18 +91,43 @@ object MediaBrowserTree { sourceUri: Uri? = null, imageUri: Uri? = null ): MediaItem { - val metadata = - MediaMetadata.Builder() - .setAlbumTitle(album) - .setTitle(title) - .setArtist(artist) - .setGenre(genre) - .setIsBrowsable(isBrowsable) - .setIsPlayable(isPlayable) - .setArtworkUri(imageUri) - .setMediaType(mediaType) - .build() + var extras = Bundle() + if( gridView ) { + extras = Bundle().apply { + putInt( + MediaConstants.EXTRAS_KEY_CONTENT_STYLE_BROWSABLE, + MediaConstants.EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM + ) + putInt( + MediaConstants.EXTRAS_KEY_CONTENT_STYLE_PLAYABLE, + MediaConstants.EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM + ) + } + } + else{ + extras = Bundle().apply { + putInt( + MediaConstants.EXTRAS_KEY_CONTENT_STYLE_BROWSABLE, + MediaConstants.EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM + ) + putInt( + MediaConstants.EXTRAS_KEY_CONTENT_STYLE_PLAYABLE, + MediaConstants.EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM + ) + } + } + val metadata = MediaMetadata.Builder() + .setAlbumTitle(album) + .setTitle(title) + .setArtist(artist) + .setGenre(genre) + .setIsBrowsable(isBrowsable) + .setIsPlayable(isPlayable) + .setArtworkUri(imageUri) + .setMediaType(mediaType) + .setExtras(extras) + .build() return MediaItem.Builder() .setMediaId(mediaId) .setSubtitleConfigurations(subtitleConfigurations) @@ -102,19 +135,57 @@ object MediaBrowserTree { .setUri(sourceUri) .build() } - - fun initialize(automotiveRepository: AutomotiveRepository) { + fun initialize( + context: Context, + automotiveRepository: AutomotiveRepository) { this.automotiveRepository = automotiveRepository - + appContext = context.applicationContext if (isInitialized) return isInitialized = true + } + + fun buildTree() { + val albumView: Boolean = Preferences.isAndroidAutoAlbumViewEnabled() + val homeView: Boolean = Preferences.isAndroidAutoHomeViewEnabled() + val playlistView: Boolean = Preferences.isAndroidAutoPlaylistViewEnabled() + val podcastView: Boolean = Preferences.isAndroidAutoPodcastViewEnabled() + val radioView: Boolean = Preferences.isAndroidAutoRadioViewEnabled() + + val tabIndex = listOf( + Preferences.getAndroidAutoFirstTab(), + Preferences.getAndroidAutoSecondTab(), + Preferences.getAndroidAutoThirdTab(), + Preferences.getAndroidAutoFourthTab() + ) + // clear before rebuild + treeNodes.clear() + + // This list must be exactly the same as the one in aa_tab_titles + val allFunctions = listOf( + HOME_ID, + LAST_PLAYED_ID, + ALBUMS_ID, + ARTISTS_ID, + PLAYLIST_ID, + PODCAST_ID, + RADIO_ID, + FOLDER_ID, + MOST_PLAYED_ID, + // RECENT_SONGS_ID, // => doesn't work ! + RECENTLY_ADDED_ID, + // MADE_FOR_YOU_ID, // => doesn't work ! + STARRED_TRACKS_ID, + STARRED_ALBUMS_ID, + STARRED_ARTISTS_ID, + RANDOM_ID + ) // Root level - treeNodes[ROOT_ID] = MediaItemNode( buildMediaItem( + gridView = albumView, title = "Root Folder", mediaId = ROOT_ID, isPlayable = false, @@ -123,192 +194,98 @@ object MediaBrowserTree { ) ) - // First level - - treeNodes[HOME_ID] = - MediaItemNode( - buildMediaItem( - title = "Home", - mediaId = HOME_ID, - isPlayable = false, - isBrowsable = true, - mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_MIXED - ) - ) - - treeNodes[LIBRARY_ID] = - MediaItemNode( - buildMediaItem( - title = "Library", - mediaId = LIBRARY_ID, - isPlayable = false, - isBrowsable = true, - mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_MIXED - ) - ) - - treeNodes[OTHER_ID] = - MediaItemNode( - buildMediaItem( - title = "Other", - mediaId = OTHER_ID, - isPlayable = false, - isBrowsable = true, - mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_MIXED - ) - ) - - treeNodes[ROOT_ID]!!.addChild(HOME_ID) - treeNodes[ROOT_ID]!!.addChild(LIBRARY_ID) - treeNodes[ROOT_ID]!!.addChild(OTHER_ID) - - // Second level HOME_ID - - treeNodes[MOST_PLAYED_ID] = - MediaItemNode( - buildMediaItem( - title = "Most played", - mediaId = MOST_PLAYED_ID, - isPlayable = false, - isBrowsable = true, - mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_ALBUMS - ) - ) - + // All available functions + // if HOME is in first place or no item is selected + if (tabIndex.firstOrNull() == 0 || tabIndex.all { it == -1 }){ + treeNodes[HOME_ID] = + MediaItemNode( + buildMediaItem( + gridView = homeView, + title = appContext.getString(R.string.aa_home), + mediaId = HOME_ID, + isPlayable = false, + isBrowsable = true, + imageUri = iconUri(R.drawable.ic_aa_home), + mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_MIXED + ) + ) + } + else { // More instead of Home + treeNodes[HOME_ID] = + MediaItemNode( + buildMediaItem( + gridView = homeView, + title = appContext.getString(R.string.aa_more), + mediaId = HOME_ID, + isPlayable = false, + isBrowsable = true, + imageUri = iconUri(R.drawable.ic_aa_other), + mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_MIXED + ) + ) + } + treeNodes[LAST_PLAYED_ID] = MediaItemNode( buildMediaItem( - title = "Last played", + gridView = albumView, + title = appContext.getString(R.string.aa_recent_albums), mediaId = LAST_PLAYED_ID, isPlayable = false, isBrowsable = true, + imageUri = iconUri(R.drawable.ic_aa_recent), mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_ALBUMS ) ) - - treeNodes[RECENTLY_ADDED_ID] = + + treeNodes[ALBUMS_ID] = MediaItemNode( buildMediaItem( - title = "Recently added", - mediaId = RECENTLY_ADDED_ID, + gridView = albumView, + title = appContext.getString(R.string.aa_albums), + mediaId = ALBUMS_ID, isPlayable = false, isBrowsable = true, + imageUri = iconUri(R.drawable.ic_aa_albums), mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_ALBUMS ) ) - - treeNodes[RECENT_SONGS_ID] = - MediaItemNode( - buildMediaItem( - title = "Recent songs", - mediaId = RECENT_SONGS_ID, - isPlayable = false, - isBrowsable = true, - mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_MIXED - ) - ) - - treeNodes[MADE_FOR_YOU_ID] = + + treeNodes[ARTISTS_ID] = MediaItemNode( buildMediaItem( - title = "Made for you", - mediaId = MADE_FOR_YOU_ID, - isPlayable = false, - isBrowsable = true, - mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_PLAYLISTS - ) - ) - - treeNodes[STARRED_TRACKS_ID] = - MediaItemNode( - buildMediaItem( - title = "Starred tracks", - mediaId = STARRED_TRACKS_ID, - isPlayable = false, - isBrowsable = true, - mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_MIXED - ) - ) - - treeNodes[STARRED_ALBUMS_ID] = - MediaItemNode( - buildMediaItem( - title = "Starred albums", - mediaId = STARRED_ALBUMS_ID, + gridView = albumView, + title = appContext.getString(R.string.aa_artists), + mediaId = ARTISTS_ID, isPlayable = false, isBrowsable = true, + imageUri = iconUri(R.drawable.ic_aa_artists), mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_ALBUMS ) ) - - treeNodes[STARRED_ARTISTS_ID] = - MediaItemNode( - buildMediaItem( - title = "Starred artists", - mediaId = STARRED_ARTISTS_ID, - isPlayable = false, - isBrowsable = true, - mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_ARTISTS - ) - ) - - treeNodes[RANDOM_ID] = - MediaItemNode( - buildMediaItem( - title = "Random", - mediaId = RANDOM_ID, - isPlayable = false, - isBrowsable = true, - mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_MIXED - ) - ) - - treeNodes[HOME_ID]!!.addChild(MOST_PLAYED_ID) - treeNodes[HOME_ID]!!.addChild(LAST_PLAYED_ID) - treeNodes[HOME_ID]!!.addChild(RECENTLY_ADDED_ID) - treeNodes[HOME_ID]!!.addChild(RECENT_SONGS_ID) - treeNodes[HOME_ID]!!.addChild(MADE_FOR_YOU_ID) - treeNodes[HOME_ID]!!.addChild(STARRED_TRACKS_ID) - treeNodes[HOME_ID]!!.addChild(STARRED_ALBUMS_ID) - treeNodes[HOME_ID]!!.addChild(STARRED_ARTISTS_ID) - treeNodes[HOME_ID]!!.addChild(RANDOM_ID) - - // Second level LIBRARY_ID - - treeNodes[FOLDER_ID] = - MediaItemNode( - buildMediaItem( - title = "Folders", - mediaId = FOLDER_ID, - isPlayable = false, - isBrowsable = true, - mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_MIXED - ) - ) - + treeNodes[PLAYLIST_ID] = MediaItemNode( buildMediaItem( - title = "Playlists", + gridView = playlistView, + title = appContext.getString(R.string.aa_playlists), mediaId = PLAYLIST_ID, isPlayable = false, isBrowsable = true, + imageUri = iconUri(R.drawable.ic_aa_playlist), mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_PLAYLISTS ) ) - treeNodes[LIBRARY_ID]!!.addChild(FOLDER_ID) - treeNodes[LIBRARY_ID]!!.addChild(PLAYLIST_ID) - - // Second level OTHER_ID - treeNodes[PODCAST_ID] = MediaItemNode( buildMediaItem( - title = "Podcasts", + gridView = podcastView, + title = appContext.getString(R.string.aa_podcast), mediaId = PODCAST_ID, isPlayable = false, isBrowsable = true, + imageUri = iconUri(R.drawable.ic_aa_podcasts), mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_PODCASTS ) ) @@ -316,18 +293,161 @@ object MediaBrowserTree { treeNodes[RADIO_ID] = MediaItemNode( buildMediaItem( - title = "Radio stations", + gridView = radioView, + title = appContext.getString(R.string.aa_radio), mediaId = RADIO_ID, isPlayable = false, isBrowsable = true, + imageUri = iconUri(R.drawable.ic_aa_radio), mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_RADIO_STATIONS ) ) - treeNodes[OTHER_ID]!!.addChild(PODCAST_ID) - treeNodes[OTHER_ID]!!.addChild(RADIO_ID) - } + treeNodes[MOST_PLAYED_ID] = + MediaItemNode( + buildMediaItem( + gridView = albumView, + title = appContext.getString(R.string.aa_album_most_played), + mediaId = MOST_PLAYED_ID, + isPlayable = false, + isBrowsable = true, + imageUri = iconUri(R.drawable.ic_aa_mostplayed), + mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_ALBUMS + ) + ) + treeNodes[RECENTLY_ADDED_ID] = + MediaItemNode( + buildMediaItem( + gridView = albumView, + title = appContext.getString(R.string.aa_album_recently_added), + mediaId = RECENTLY_ADDED_ID, + isPlayable = false, + isBrowsable = true, + imageUri = iconUri(R.drawable.ic_aa_added_album), + mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_ALBUMS + ) + ) + + treeNodes[RECENT_SONGS_ID] = + MediaItemNode( + buildMediaItem( + gridView = albumView, + title = appContext.getString(R.string.aa_song_recently_played), + mediaId = RECENT_SONGS_ID, + isPlayable = false, + isBrowsable = true, + imageUri = iconUri(R.drawable.ic_aa_recent_title), + mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_MIXED + ) + ) + + treeNodes[MADE_FOR_YOU_ID] = + MediaItemNode( + buildMediaItem( + gridView = albumView, + title = appContext.getString(R.string.aa_made_for_you), + mediaId = MADE_FOR_YOU_ID, + isPlayable = false, + isBrowsable = true, + imageUri = iconUri(R.drawable.ic_aa_for_you), + mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_PLAYLISTS + ) + ) + treeNodes[STARRED_TRACKS_ID] = + MediaItemNode( + buildMediaItem( + gridView = albumView, + title = appContext.getString(R.string.aa_starred_tracks), + mediaId = STARRED_TRACKS_ID, + isPlayable = false, + isBrowsable = true, + imageUri = iconUri(R.drawable.ic_aa_star_title), + mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_MIXED + ) + ) + + treeNodes[STARRED_ALBUMS_ID] = + MediaItemNode( + buildMediaItem( + gridView = albumView, + title = appContext.getString(R.string.aa_starred_albums), + mediaId = STARRED_ALBUMS_ID, + isPlayable = false, + isBrowsable = true, + imageUri = iconUri(R.drawable.ic_aa_star_album), + mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_ALBUMS + ) + ) + + treeNodes[STARRED_ARTISTS_ID] = + MediaItemNode( + buildMediaItem( + gridView = albumView, + title = appContext.getString(R.string.aa_starred_artists), + mediaId = STARRED_ARTISTS_ID, + isPlayable = false, + isBrowsable = true, + imageUri = iconUri(R.drawable.ic_aa_artists), + mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_ARTISTS + ) + ) + + treeNodes[FOLDER_ID] = + MediaItemNode( + buildMediaItem( + gridView = false, + title = appContext.getString(R.string.aa_music_folder), + mediaId = FOLDER_ID, + isPlayable = false, + isBrowsable = true, + imageUri = iconUri(R.drawable.ic_aa_folders), + mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_MIXED + ) + ) + + treeNodes[RANDOM_ID] = + MediaItemNode( + buildMediaItem( + gridView = albumView, + title = appContext.getString(R.string.aa_random), + mediaId = RANDOM_ID, + isPlayable = false, + isBrowsable = true, + imageUri = iconUri(R.drawable.ic_aa_random), + mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_MIXED + ) + ) + + val root = treeNodes[ROOT_ID]!! + val selectedIds = mutableSetOf() + + // First level + // add functions selected by user for the 4 tabs + tabIndex + .filter { it != -1 } + .forEach { index -> + allFunctions.getOrNull(index)?.let { function -> + if (selectedIds.add(function)) { + root.addChild(function) + } + } + } + // if no function is selected, add at least HOME_ID + if (selectedIds.isEmpty()) { + root.addChild(HOME_ID) + selectedIds.add(HOME_ID) + } + + // Second level for HOME_ID even there is no HOME_ID displayed + // add all functions not previously added + allFunctions + .filter { it !in selectedIds } + .forEach { function -> + treeNodes[HOME_ID]?.addChild(function) + } + } + fun getRootItem(): MediaItem { return treeNodes[ROOT_ID]!!.item } @@ -337,125 +457,83 @@ object MediaBrowserTree { ): ListenableFuture>> { return when (id) { ROOT_ID -> treeNodes[ROOT_ID]?.getChildren()!! - HOME_ID -> treeNodes[HOME_ID]?.getChildren()!! - LIBRARY_ID -> treeNodes[LIBRARY_ID]?.getChildren()!! - OTHER_ID -> treeNodes[OTHER_ID]?.getChildren()!! - MOST_PLAYED_ID -> automotiveRepository.getAlbums(id, "frequent", 100) - LAST_PLAYED_ID -> automotiveRepository.getAlbums(id, "recent", 100) - RECENTLY_ADDED_ID -> automotiveRepository.getAlbums(id, "newest", 100) - RECENT_SONGS_ID -> automotiveRepository.getRecentlyPlayedSongs(getServerId(),100) + HOME_ID -> treeNodes[HOME_ID]?.getChildren()!! + LAST_PLAYED_ID -> automotiveRepository.getAlbums(id, "recent", 15) + ALBUMS_ID -> automotiveRepository.getAlbums(id, "alphabeticalByName", 500) + ARTISTS_ID -> automotiveRepository.getAlbums(id, "alphabeticalByArtist", 500) + PLAYLIST_ID -> automotiveRepository.getPlaylists(id) + PODCAST_ID -> automotiveRepository.getNewestPodcastEpisodes(100) + RADIO_ID -> automotiveRepository.internetRadioStations + FOLDER_ID -> automotiveRepository.getMusicFolders(id) + MOST_PLAYED_ID -> automotiveRepository.getAlbums(id, "frequent", 15) + RECENT_SONGS_ID -> automotiveRepository.getRecentlyPlayedSongs(getServerId(),30) + RECENTLY_ADDED_ID -> automotiveRepository.getAlbums(id, "newest", 15) MADE_FOR_YOU_ID -> automotiveRepository.getStarredArtists(id) STARRED_TRACKS_ID -> automotiveRepository.starredSongs STARRED_ALBUMS_ID -> automotiveRepository.getStarredAlbums(id) STARRED_ARTISTS_ID -> automotiveRepository.getStarredArtists(id) RANDOM_ID -> automotiveRepository.getRandomSongs(100) - FOLDER_ID -> automotiveRepository.getMusicFolders(id) - PLAYLIST_ID -> automotiveRepository.getPlaylists(id) - PODCAST_ID -> automotiveRepository.getNewestPodcastEpisodes(100) - RADIO_ID -> automotiveRepository.internetRadioStations else -> { - if (id.startsWith(MOST_PLAYED_ID)) { - return automotiveRepository.getAlbumTracks( - id.removePrefix( - MOST_PLAYED_ID - ) - ) + if (id.startsWith(LAST_PLAYED_ID)) { + return automotiveRepository.getAlbumTracks(id.removePrefix(LAST_PLAYED_ID)) } - if (id.startsWith(LAST_PLAYED_ID)) { - return automotiveRepository.getAlbumTracks( - id.removePrefix( - LAST_PLAYED_ID - ) - ) + if (id.startsWith(ALBUMS_ID)) { + return automotiveRepository.getAlbumTracks(id.removePrefix(ALBUMS_ID)) + } + + if (id.startsWith(ARTISTS_ID)) { + return automotiveRepository.getAlbumTracks(id.removePrefix(ARTISTS_ID)) + } + + if (id.startsWith(HOME_ID)) { + return automotiveRepository.getAlbumTracks(id.removePrefix(HOME_ID)) + } + + if (id.startsWith(MOST_PLAYED_ID)) { + return automotiveRepository.getAlbumTracks(id.removePrefix(MOST_PLAYED_ID)) } if (id.startsWith(RECENTLY_ADDED_ID)) { - return automotiveRepository.getAlbumTracks( - id.removePrefix( - RECENTLY_ADDED_ID - ) - ) + return automotiveRepository.getAlbumTracks(id.removePrefix(RECENTLY_ADDED_ID)) } if (id.startsWith(MADE_FOR_YOU_ID)) { - return automotiveRepository.getMadeForYou( - id.removePrefix( - MADE_FOR_YOU_ID - ), - 20 - ) + return automotiveRepository.getMadeForYou(id.removePrefix(MADE_FOR_YOU_ID),20) } if (id.startsWith(STARRED_ALBUMS_ID)) { - return automotiveRepository.getAlbumTracks( - id.removePrefix( - STARRED_ALBUMS_ID - ) - ) + return automotiveRepository.getAlbumTracks(id.removePrefix(STARRED_ALBUMS_ID)) } if (id.startsWith(STARRED_ARTISTS_ID)) { - return automotiveRepository.getArtistAlbum( - STARRED_ALBUMS_ID, - id.removePrefix( - STARRED_ARTISTS_ID - ) - ) - } - - if (id.startsWith(FOLDER_ID)) { - return automotiveRepository.getIndexes( - INDEX_ID, - id.removePrefix( - FOLDER_ID - ) - ) - } - - if (id.startsWith(INDEX_ID)) { - return automotiveRepository.getDirectories( - DIRECTORY_ID, - id.removePrefix( - INDEX_ID - ) - ) - } - - if (id.startsWith(DIRECTORY_ID)) { - return automotiveRepository.getDirectories( - DIRECTORY_ID, - id.removePrefix( - DIRECTORY_ID - ) - ) + return automotiveRepository.getArtistAlbum(STARRED_ALBUMS_ID,id.removePrefix(STARRED_ARTISTS_ID)) } if (id.startsWith(PLAYLIST_ID)) { - return automotiveRepository.getPlaylistSongs( - id.removePrefix( - PLAYLIST_ID - ) - ) + return automotiveRepository.getPlaylistSongs(id.removePrefix(PLAYLIST_ID)) } if (id.startsWith(ALBUM_ID)) { - return automotiveRepository.getAlbumTracks( - id.removePrefix( - ALBUM_ID - ) - ) + return automotiveRepository.getAlbumTracks(id.removePrefix(ALBUM_ID)) } if (id.startsWith(ARTIST_ID)) { - return automotiveRepository.getArtistAlbum( - ALBUM_ID, - id.removePrefix( - ARTIST_ID - ) - ) + return automotiveRepository.getArtistAlbum(ALBUM_ID,id.removePrefix(ARTIST_ID)) + } + + if (id.startsWith(FOLDER_ID)) { + return automotiveRepository.getIndexes(INDEX_ID,id.removePrefix(FOLDER_ID)) + } + + if (id.startsWith(INDEX_ID)) { + return automotiveRepository.getDirectories(DIRECTORY_ID,id.removePrefix(INDEX_ID)) + } + + if (id.startsWith(DIRECTORY_ID)) { + return automotiveRepository.getDirectories(DIRECTORY_ID,id.removePrefix(DIRECTORY_ID)) } return Futures.immediateFuture(LibraryResult.ofError(LibraryResult.RESULT_ERROR_BAD_VALUE)) @@ -490,6 +568,7 @@ object MediaBrowserTree { fun search(query: String): ListenableFuture>> { return automotiveRepository.search( query, + // ALBUM_ID, ALBUM_ID, ARTIST_ID ) diff --git a/app/src/tempus/java/com/cappielloantonio/tempo/service/MediaLibraryServiceCallback.kt b/app/src/tempus/java/com/cappielloantonio/tempo/service/MediaLibraryServiceCallback.kt index a68fa713..b8988d68 100644 --- a/app/src/tempus/java/com/cappielloantonio/tempo/service/MediaLibraryServiceCallback.kt +++ b/app/src/tempus/java/com/cappielloantonio/tempo/service/MediaLibraryServiceCallback.kt @@ -47,7 +47,8 @@ open class MediaLibrarySessionCallback( MediaLibraryService.MediaLibrarySession.Callback { init { - MediaBrowserTree.initialize(automotiveRepository) + // modified by MFO + MediaBrowserTree.initialize(context, automotiveRepository) } private val customCommandToggleShuffleModeOn = CommandButton.Builder() @@ -348,6 +349,8 @@ open class MediaLibrarySessionCallback( browser: MediaSession.ControllerInfo, params: MediaLibraryService.LibraryParams? ): ListenableFuture> { + // added by MFO + MediaBrowserTree.buildTree() return Futures.immediateFuture(LibraryResult.ofItem(MediaBrowserTree.getRootItem(), params)) }