diff --git a/app/src/main/java/org/oxycblt/auxio/AuxioService.kt b/app/src/main/java/org/oxycblt/auxio/AuxioService.kt index 5f8cbbe6f..da79b8a11 100644 --- a/app/src/main/java/org/oxycblt/auxio/AuxioService.kt +++ b/app/src/main/java/org/oxycblt/auxio/AuxioService.kt @@ -36,6 +36,7 @@ import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject import org.oxycblt.auxio.music.service.MusicServiceFragment import org.oxycblt.auxio.playback.service.PlaybackServiceFragment +import org.oxycblt.auxio.util.logD @AndroidEntryPoint class AuxioService : @@ -149,6 +150,7 @@ class AuxioService : } override fun invalidateMusic(mediaId: String) { + logD(mediaId) notifyChildrenChanged(mediaId) } diff --git a/app/src/main/java/org/oxycblt/auxio/detail/DetailGenerator.kt b/app/src/main/java/org/oxycblt/auxio/detail/DetailGenerator.kt index 0a4ffd379..348badcdb 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/DetailGenerator.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/DetailGenerator.kt @@ -205,7 +205,7 @@ sealed interface DetailSection { data class Artists(override val items: List) : PlainSection() { override val order = 0 - override val stringRes = R.string.lbl_songs + override val stringRes = R.string.lbl_artists } data class Albums(val category: Category, override val items: List) : diff --git a/app/src/main/java/org/oxycblt/auxio/music/service/MediaItemTranslation.kt b/app/src/main/java/org/oxycblt/auxio/music/service/MediaItemTranslation.kt index 421405123..48488a376 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/service/MediaItemTranslation.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/service/MediaItemTranslation.kt @@ -47,10 +47,6 @@ sealed interface MediaSessionUID { override fun toString() = "$ID_ITEM:$uid" } - data class ChildItem(val parentUid: Music.UID, val childUid: Music.UID) : MediaSessionUID { - override fun toString() = "$ID_ITEM:$parentUid>$childUid" - } - companion object { const val ID_CATEGORY = BuildConfig.APPLICATION_ID + ".category" const val ID_ITEM = BuildConfig.APPLICATION_ID + ".item" @@ -62,16 +58,7 @@ sealed interface MediaSessionUID { } return when (parts[0]) { ID_CATEGORY -> Tab(TabNode.fromString(parts[1]) ?: return null) - ID_ITEM -> { - val uids = parts[1].split(">", limit = 2) - if (uids.size == 1) { - Music.UID.fromString(uids[0])?.let { SingleItem(it) } - } else { - Music.UID.fromString(uids[0])?.let { parent -> - Music.UID.fromString(uids[1])?.let { child -> ChildItem(parent, child) } - } - } - } + ID_ITEM -> SingleItem(Music.UID.fromString(parts[1]) ?: return null) else -> return null } } @@ -89,6 +76,10 @@ fun header(name: String): Sugar = { putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, name) } +fun child(of: MusicParent): Sugar = { + putString(MusicBrowser.KEY_CHILD_OF, MediaSessionUID.SingleItem(of.uid).toString()) +} + private fun style(style: Int): Sugar = { putInt(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM, style) } @@ -115,17 +106,8 @@ fun TabNode.toMediaItem(context: Context): MediaItem { return MediaItem(description.build(), MediaItem.FLAG_BROWSABLE) } -fun Song.toMediaDescription( - context: Context, - parent: MusicParent? = null, - vararg sugar: Sugar -): MediaDescriptionCompat { - val mediaSessionUID = - if (parent == null) { - MediaSessionUID.SingleItem(uid) - } else { - MediaSessionUID.ChildItem(parent.uid, uid) - } +fun Song.toMediaDescription(context: Context, vararg sugar: Sugar): MediaDescriptionCompat { + val mediaSessionUID = MediaSessionUID.SingleItem(uid) val extras = makeExtras(context, *sugar) return MediaDescriptionCompat.Builder() .setMediaId(mediaSessionUID.toString()) @@ -138,25 +120,12 @@ fun Song.toMediaDescription( .build() } -fun Song.toMediaItem( - context: Context, - parent: MusicParent? = null, - vararg sugar: Sugar -): MediaItem { - return MediaItem(toMediaDescription(context, parent, *sugar), MediaItem.FLAG_PLAYABLE) +fun Song.toMediaItem(context: Context, vararg sugar: Sugar): MediaItem { + return MediaItem(toMediaDescription(context, *sugar), MediaItem.FLAG_PLAYABLE) } -fun Album.toMediaItem( - context: Context, - parent: MusicParent? = null, - vararg sugar: Sugar -): MediaItem { - val mediaSessionUID = - if (parent == null) { - MediaSessionUID.SingleItem(uid) - } else { - MediaSessionUID.ChildItem(parent.uid, uid) - } +fun Album.toMediaItem(context: Context, vararg sugar: Sugar): MediaItem { + val mediaSessionUID = MediaSessionUID.SingleItem(uid) val extras = makeExtras(context, *sugar) val counts = context.getPlural(R.plurals.fmt_song_count, songs.size) val description = diff --git a/app/src/main/java/org/oxycblt/auxio/music/service/MusicBrowser.kt b/app/src/main/java/org/oxycblt/auxio/music/service/MusicBrowser.kt index bccdef87c..caffe0688 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/service/MusicBrowser.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/service/MusicBrowser.kt @@ -21,6 +21,7 @@ package org.oxycblt.auxio.music.service import android.content.Context import android.support.v4.media.MediaBrowserCompat.MediaItem import javax.inject.Inject +import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.R import org.oxycblt.auxio.detail.DetailGenerator import org.oxycblt.auxio.detail.DetailSection @@ -117,8 +118,6 @@ private constructor( is MediaSessionUID.Tab -> return uid.node.toMediaItem(context) is MediaSessionUID.SingleItem -> musicRepository.find(uid.uid)?.let { musicRepository.find(it.uid) } - is MediaSessionUID.ChildItem -> - musicRepository.find(uid.childUid)?.let { musicRepository.find(it.uid) } null -> null } ?: return null @@ -128,7 +127,7 @@ private constructor( is Artist -> music.toMediaItem(context) is Genre -> music.toMediaItem(context) is Playlist -> music.toMediaItem(context) - is Song -> music.toMediaItem(context, null) + is Song -> music.toMediaItem(context) } } @@ -160,10 +159,10 @@ private constructor( private fun SearchEngine.Items.toMediaItems(): MutableList { val music = mutableListOf() if (songs != null) { - music.addAll(songs.map { it.toMediaItem(context, null, header(R.string.lbl_songs)) }) + music.addAll(songs.map { it.toMediaItem(context, header(R.string.lbl_songs)) }) } if (albums != null) { - music.addAll(albums.map { it.toMediaItem(context, null, header(R.string.lbl_albums)) }) + music.addAll(albums.map { it.toMediaItem(context, header(R.string.lbl_albums)) }) } if (artists != null) { music.addAll(artists.map { it.toMediaItem(context, header(R.string.lbl_artists)) }) @@ -185,9 +184,6 @@ private constructor( is MediaSessionUID.SingleItem -> { getChildMediaItems(mediaSessionUID.uid) } - is MediaSessionUID.ChildItem -> { - getChildMediaItems(mediaSessionUID.childUid) - } null -> { return null } @@ -208,11 +204,11 @@ private constructor( } is TabNode.More -> { val tabs = homeGenerator.tabs() - tabs.takeLast(tabs.size - maxTabs).map { TabNode.Home(it).toMediaItem(context) } + tabs.takeLast(tabs.size - maxTabs + 1).map { TabNode.Home(it).toMediaItem(context) } } is TabNode.Home -> when (node.type) { - MusicType.SONGS -> homeGenerator.songs().map { it.toMediaItem(context, null) } + MusicType.SONGS -> homeGenerator.songs().map { it.toMediaItem(context) } MusicType.ALBUMS -> homeGenerator.albums().map { it.toMediaItem(context) } MusicType.ARTISTS -> homeGenerator.artists().map { it.toMediaItem(context) } MusicType.GENRES -> homeGenerator.genres().map { it.toMediaItem(context) } @@ -225,18 +221,24 @@ private constructor( return detail.sections.flatMap { section -> when (section) { is DetailSection.Songs -> - section.items.map { it.toMediaItem(context, null, header(section.stringRes)) } + section.items.map { + it.toMediaItem(context, header(section.stringRes), child(detail.parent)) + } is DetailSection.Albums -> - section.items.map { it.toMediaItem(context, null, header(section.stringRes)) } + section.items.map { it.toMediaItem(context, header(section.stringRes)) } is DetailSection.Artists -> section.items.map { it.toMediaItem(context, header(section.stringRes)) } is DetailSection.Discs -> section.discs.flatMap { (disc, songs) -> val discString = disc.resolveNumber(context) - songs.map { it.toMediaItem(context, null, header(discString)) } + songs.map { it.toMediaItem(context, header(discString)) } } else -> error("Unknown section type: $section") } } } + + companion object { + const val KEY_CHILD_OF = BuildConfig.APPLICATION_ID + ".key.CHILD_OF" + } } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/service/MediaSessionHolder.kt b/app/src/main/java/org/oxycblt/auxio/playback/service/MediaSessionHolder.kt index 9d3af9bab..b5724f6b4 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/service/MediaSessionHolder.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/service/MediaSessionHolder.kt @@ -295,7 +295,7 @@ private constructor( queue.mapIndexed { i, song -> val description = song.toMediaDescription( - context, null, { putInt(MediaSessionInterface.KEY_QUEUE_POS, i) }) + context, { putInt(MediaSessionInterface.KEY_QUEUE_POS, i) }) // Store the item index so we can then use the analogous index in the // playback state. MediaSessionCompat.QueueItem(description, i.toLong()) diff --git a/app/src/main/java/org/oxycblt/auxio/playback/service/MediaSessionInterface.kt b/app/src/main/java/org/oxycblt/auxio/playback/service/MediaSessionInterface.kt index 38153be4a..2ea4f8db2 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/service/MediaSessionInterface.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/service/MediaSessionInterface.kt @@ -41,11 +41,13 @@ import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.device.DeviceLibrary import org.oxycblt.auxio.music.info.Name import org.oxycblt.auxio.music.service.MediaSessionUID +import org.oxycblt.auxio.music.service.MusicBrowser import org.oxycblt.auxio.music.user.UserLibrary import org.oxycblt.auxio.playback.state.PlaybackCommand import org.oxycblt.auxio.playback.state.PlaybackStateManager import org.oxycblt.auxio.playback.state.RepeatMode import org.oxycblt.auxio.playback.state.ShuffleMode +import org.oxycblt.auxio.util.logD class MediaSessionInterface @Inject @@ -80,7 +82,10 @@ constructor( override fun onPlayFromMediaId(mediaId: String?, extras: Bundle?) { super.onPlayFromMediaId(mediaId, extras) val uid = MediaSessionUID.fromString(mediaId ?: return) ?: return - val command = expandUidIntoCommand(uid) + val parentUid = + extras?.getString(MusicBrowser.KEY_CHILD_OF)?.let { MediaSessionUID.fromString(it) } + val command = expandUidIntoCommand(uid, parentUid) + logD(extras?.getString(MusicBrowser.KEY_CHILD_OF)) playbackManager.play(requireNotNull(command) { "Invalid playback configuration" }) } @@ -105,7 +110,6 @@ constructor( val songUid = when (uid) { is MediaSessionUID.SingleItem -> uid.uid - is MediaSessionUID.ChildItem -> uid.childUid else -> return } val song = deviceLibrary.songs.find { it.uid == songUid } ?: return @@ -126,7 +130,6 @@ constructor( val songUid = when (uid) { is MediaSessionUID.SingleItem -> uid.uid - is MediaSessionUID.ChildItem -> uid.childUid else -> return } val firstAt = playbackManager.queue.indexOfFirst { it.uid == songUid } @@ -194,20 +197,14 @@ constructor( context.sendBroadcast(Intent(action)) } - private fun expandUidIntoCommand(uid: MediaSessionUID): PlaybackCommand? { - val music: Music - var parent: MusicParent? = null - when (uid) { - is MediaSessionUID.SingleItem -> { - music = musicRepository.find(uid.uid) ?: return null - } - is MediaSessionUID.ChildItem -> { - music = musicRepository.find(uid.childUid) ?: return null - parent = musicRepository.find(uid.parentUid) as? MusicParent ?: return null - } - else -> return null - } - + private fun expandUidIntoCommand( + uid: MediaSessionUID, + parentUid: MediaSessionUID? + ): PlaybackCommand? { + val unwrappedUid = (uid as? MediaSessionUID.SingleItem)?.uid ?: return null + val unwrappedParentUid = (parentUid as? MediaSessionUID.SingleItem)?.uid + val music = musicRepository.find(unwrappedUid) ?: return null + val parent = unwrappedParentUid?.let { musicRepository.find(it) as? MusicParent } return expandMusicIntoCommand(music, parent) }