playback: refactor navigation commands

Unify the artist and genre picker commands into a single event
(like others), and also make the playback panel correctly respond to
album/artist navigation events.
This commit is contained in:
Alexander Capehart 2023-07-04 14:24:46 -06:00
parent a6a3eceb7b
commit 9e5b737d1a
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
11 changed files with 197 additions and 148 deletions

View file

@ -42,7 +42,7 @@ import org.oxycblt.auxio.detail.DetailViewModel
import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.Panel
import org.oxycblt.auxio.playback.OpenPanel
import org.oxycblt.auxio.playback.PlaybackBottomSheetBehavior
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.queue.QueueBottomSheetBehavior
@ -300,13 +300,13 @@ class MainFragment :
}
}
private fun handlePanel(panel: Panel?) {
private fun handlePanel(panel: OpenPanel?) {
if (panel == null) return
logD("Trying to update panel to $panel")
when (panel) {
is Panel.Main -> tryClosePlaybackPanel()
is Panel.Playback -> tryOpenPlaybackPanel()
is Panel.Queue -> tryOpenQueuePanel()
is OpenPanel.Main -> tryClosePlaybackPanel()
is OpenPanel.Playback -> tryOpenPlaybackPanel()
is OpenPanel.Queue -> tryOpenQueuePanel()
}
playbackModel.openPanel.consume()
}

View file

@ -51,6 +51,7 @@ import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.PlaylistDecision
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.info.Disc
import org.oxycblt.auxio.playback.PlaybackDecision
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.util.canScroll
import org.oxycblt.auxio.util.collect
@ -129,11 +130,10 @@ class AlbumDetailFragment :
collect(detailModel.toShow.flow, ::handleShow)
collect(menuModel.pendingMenu.flow, ::handleMenu)
collectImmediately(selectionModel.selected, ::updateSelection)
collect(musicModel.playlistDecision.flow, ::handleDecision)
collect(musicModel.playlistDecision.flow, ::handlePlaylistDecision)
collectImmediately(
playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback)
collect(playbackModel.artistPickerSong.flow, ::handlePlayFromArtist)
collect(playbackModel.genrePickerSong.flow, ::handlePlayFromGenre)
collect(playbackModel.playbackDecision.flow, ::handlePlaybackDecision)
}
override fun onDestroyBinding(binding: FragmentDetailBinding) {
@ -331,7 +331,7 @@ class AlbumDetailFragment :
}
}
private fun handleDecision(decision: PlaylistDecision?) {
private fun handlePlaylistDecision(decision: PlaylistDecision?) {
if (decision == null) return
val directions =
when (decision) {
@ -342,7 +342,7 @@ class AlbumDetailFragment :
}
is PlaylistDecision.New,
is PlaylistDecision.Rename,
is PlaylistDecision.Delete -> error("Unexpected decision $decision")
is PlaylistDecision.Delete -> error("Unexpected playlist decision $decision")
}
findNavController().navigateSafe(directions)
}
@ -352,16 +352,20 @@ class AlbumDetailFragment :
song.takeIf { parent == detailModel.currentAlbum.value }, isPlaying)
}
private fun handlePlayFromArtist(song: Song?) {
if (song == null) return
logD("Launching play from artist dialog for $song")
findNavController().navigateSafe(AlbumDetailFragmentDirections.playFromArtist(song.uid))
private fun handlePlaybackDecision(decision: PlaybackDecision?) {
if (decision == null) return
val directions =
when (decision) {
is PlaybackDecision.PlayFromArtist -> {
logD("Launching play from artist dialog for $decision")
AlbumDetailFragmentDirections.playFromArtist(decision.song.uid)
}
private fun handlePlayFromGenre(song: Song?) {
if (song == null) return
logD("Launching play from genre dialog for $song")
findNavController().navigateSafe(AlbumDetailFragmentDirections.playFromGenre(song.uid))
is PlaybackDecision.PlayFromGenre -> {
logD("Launching play from artist dialog for $decision")
AlbumDetailFragmentDirections.playFromGenre(decision.song.uid)
}
}
findNavController().navigateSafe(directions)
}
private fun scrollToAlbumSong(song: Song) {

View file

@ -50,6 +50,7 @@ import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.PlaylistDecision
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackDecision
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.util.collect
import org.oxycblt.auxio.util.collectImmediately
@ -130,11 +131,10 @@ class ArtistDetailFragment :
collect(detailModel.toShow.flow, ::handleShow)
collect(menuModel.pendingMenu.flow, ::handleMenu)
collectImmediately(selectionModel.selected, ::updateSelection)
collect(musicModel.playlistDecision.flow, ::handleDecision)
collect(musicModel.playlistDecision.flow, ::handlePlaylistDecision)
collectImmediately(
playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback)
collect(playbackModel.artistPickerSong.flow, ::handlePlayFromArtist)
collect(playbackModel.genrePickerSong.flow, ::handlePlayFromGenre)
collect(playbackModel.playbackDecision.flow, ::handlePlaybackDecision)
}
override fun onDestroyBinding(binding: FragmentDetailBinding) {
@ -343,7 +343,7 @@ class ArtistDetailFragment :
}
}
private fun handleDecision(decision: PlaylistDecision?) {
private fun handlePlaylistDecision(decision: PlaylistDecision?) {
if (decision == null) return
val directions =
when (decision) {
@ -354,7 +354,7 @@ class ArtistDetailFragment :
}
is PlaylistDecision.New,
is PlaylistDecision.Rename,
is PlaylistDecision.Delete -> error("Unexpected decision $decision")
is PlaylistDecision.Delete -> error("Unexpected playlist decision $decision")
}
findNavController().navigateSafe(directions)
}
@ -374,15 +374,17 @@ class ArtistDetailFragment :
artistListAdapter.setPlaying(playingItem, isPlaying)
}
private fun handlePlayFromArtist(song: Song?) {
if (song == null) return
logD("Launching play from artist dialog for $song")
findNavController().navigateSafe(AlbumDetailFragmentDirections.playFromArtist(song.uid))
private fun handlePlaybackDecision(decision: PlaybackDecision?) {
if (decision == null) return
val directions =
when (decision) {
is PlaybackDecision.PlayFromArtist ->
error("Unexpected playback decision $decision")
is PlaybackDecision.PlayFromGenre -> {
logD("Launching play from artist dialog for $decision")
ArtistDetailFragmentDirections.playFromGenre(decision.song.uid)
}
private fun handlePlayFromGenre(song: Song?) {
if (song == null) return
logD("Launching play from genre dialog for $song")
findNavController().navigateSafe(AlbumDetailFragmentDirections.playFromGenre(song.uid))
}
findNavController().navigateSafe(directions)
}
}

View file

@ -50,6 +50,7 @@ import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.PlaylistDecision
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackDecision
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.util.collect
import org.oxycblt.auxio.util.collectImmediately
@ -131,8 +132,7 @@ class GenreDetailFragment :
collect(musicModel.playlistDecision.flow, ::handleDecision)
collectImmediately(
playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback)
collect(playbackModel.artistPickerSong.flow, ::handlePlayFromArtist)
collect(playbackModel.genrePickerSong.flow, ::handlePlayFromGenre)
collect(playbackModel.playbackDecision.flow, ::handlePlaybackDecision)
}
override fun onDestroyBinding(binding: FragmentDetailBinding) {
@ -337,12 +337,12 @@ class GenreDetailFragment :
when (decision) {
is PlaylistDecision.Add -> {
logD("Adding ${decision.songs.size} songs to a playlist")
ArtistDetailFragmentDirections.addToPlaylist(
GenreDetailFragmentDirections.addToPlaylist(
decision.songs.map { it.uid }.toTypedArray())
}
is PlaylistDecision.New,
is PlaylistDecision.Rename,
is PlaylistDecision.Delete -> error("Unexpected decision $decision")
is PlaylistDecision.Delete -> error("Unexpected playlist decision $decision")
}
findNavController().navigateSafe(directions)
}
@ -362,15 +362,16 @@ class GenreDetailFragment :
genreListAdapter.setPlaying(playingItem, isPlaying)
}
private fun handlePlayFromArtist(song: Song?) {
if (song == null) return
logD("Launching play from artist dialog for $song")
findNavController().navigateSafe(AlbumDetailFragmentDirections.playFromArtist(song.uid))
private fun handlePlaybackDecision(decision: PlaybackDecision?) {
if (decision == null) return
val directions =
when (decision) {
is PlaybackDecision.PlayFromArtist -> {
logD("Launching play from artist dialog for $decision")
GenreDetailFragmentDirections.playFromArtist(decision.song.uid)
}
private fun handlePlayFromGenre(song: Song?) {
if (song == null) return
logD("Launching play from genre dialog for $song")
findNavController().navigateSafe(AlbumDetailFragmentDirections.playFromGenre(song.uid))
is PlaybackDecision.PlayFromGenre -> error("Unexpected playback decision $decision")
}
findNavController().navigateSafe(directions)
}
}

View file

@ -52,6 +52,7 @@ import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.PlaylistDecision
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackDecision
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.util.collect
import org.oxycblt.auxio.util.collectImmediately
@ -146,8 +147,7 @@ class PlaylistDetailFragment :
collect(musicModel.playlistDecision.flow, ::handleDecision)
collectImmediately(
playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback)
collect(playbackModel.artistPickerSong.flow, ::handlePlayFromArtist)
collect(playbackModel.genrePickerSong.flow, ::handlePlayFromGenre)
collect(playbackModel.playbackDecision.flow, ::handlePlaybackDecision)
}
override fun onStart() {
@ -387,7 +387,7 @@ class PlaylistDetailFragment :
PlaylistDetailFragmentDirections.deletePlaylist(decision.playlist.uid)
}
is PlaylistDecision.Add,
is PlaylistDecision.New -> error("Unexpected decision $decision")
is PlaylistDecision.New -> error("Unexpected playlist decision $decision")
}
findNavController().navigateSafe(directions)
}
@ -398,17 +398,22 @@ class PlaylistDetailFragment :
song.takeIf { parent == detailModel.currentPlaylist.value }, isPlaying)
}
private fun handlePlayFromArtist(song: Song?) {
if (song == null) return
logD("Launching play from artist dialog for $song")
findNavController().navigateSafe(AlbumDetailFragmentDirections.playFromArtist(song.uid))
private fun handlePlaybackDecision(decision: PlaybackDecision?) {
if (decision == null) return
val directions =
when (decision) {
is PlaybackDecision.PlayFromArtist -> {
logD("Launching play from artist dialog for $decision")
PlaylistDetailFragmentDirections.playFromArtist(decision.song.uid)
}
is PlaybackDecision.PlayFromGenre -> {
logD("Launching play from artist dialog for $decision")
PlaylistDetailFragmentDirections.playFromGenre(decision.song.uid)
}
}
findNavController().navigateSafe(directions)
}
private fun handlePlayFromGenre(song: Song?) {
if (song == null) return
logD("Launching play from genre dialog for $song")
findNavController().navigateSafe(AlbumDetailFragmentDirections.playFromGenre(song.uid))
}
private fun updateMultiToolbar() {
val id =
when {

View file

@ -69,7 +69,7 @@ class ShowArtistDialog :
detailModel.toShow.consume()
pickerModel.setArtistChoiceUid(args.itemUid)
collectImmediately(pickerModel.artistChoices, ::handleChoices)
collectImmediately(pickerModel.artistChoices, ::updateChoices)
}
override fun onDestroyBinding(binding: DialogMusicChoicesBinding) {
@ -83,7 +83,7 @@ class ShowArtistDialog :
detailModel.showArtist(item)
}
private fun handleChoices(choices: ArtistShowChoices?) {
private fun updateChoices(choices: ArtistShowChoices?) {
if (choices == null) {
logD("No choices to show, navigating away")
findNavController().navigateUp()

View file

@ -33,6 +33,7 @@ import dagger.hilt.android.AndroidEntryPoint
import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentPlaybackPanelBinding
import org.oxycblt.auxio.detail.DetailViewModel
import org.oxycblt.auxio.detail.Show
import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.Song
@ -40,6 +41,7 @@ import org.oxycblt.auxio.music.resolveNames
import org.oxycblt.auxio.playback.state.RepeatMode
import org.oxycblt.auxio.playback.ui.StyledSeekBar
import org.oxycblt.auxio.ui.ViewBindingFragment
import org.oxycblt.auxio.util.collect
import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.share
@ -129,6 +131,7 @@ class PlaybackPanelFragment :
collectImmediately(playbackModel.repeatMode, ::updateRepeat)
collectImmediately(playbackModel.isPlaying, ::updatePlaying)
collectImmediately(playbackModel.isShuffled, ::updateShuffled)
collect(detailModel.toShow.flow, ::handleShow)
}
override fun onDestroyBinding(binding: FragmentPlaybackPanelBinding) {
@ -233,17 +236,25 @@ class PlaybackPanelFragment :
requireBinding().playbackShuffle.isActivated = isShuffled
}
private fun navigateToCurrentArtist() {
playbackModel.song.value?.let {
detailModel.showArtist(it)
playbackModel.openMain()
private fun handleShow(show: Show?) {
when (show) {
is Show.ArtistDetails,
is Show.AlbumDetails -> playbackModel.openMain()
is Show.SongDetails,
is Show.SongAlbumDetails,
is Show.SongArtistDetails,
is Show.AlbumArtistDetails,
is Show.GenreDetails,
is Show.PlaylistDetails,
null -> {}
}
}
private fun navigateToCurrentAlbum() {
playbackModel.song.value?.let {
detailModel.showAlbum(it.album)
playbackModel.openMain()
private fun navigateToCurrentArtist() {
playbackModel.song.value?.let(detailModel::showArtist)
}
private fun navigateToCurrentAlbum() {
playbackModel.song.value?.let { detailModel.showAlbum(it.album) }
}
}

View file

@ -89,31 +89,15 @@ constructor(
val isShuffled: StateFlow<Boolean>
get() = _isShuffled
private val _openPanel = MutableEvent<Panel>()
val openPanel: Event<Panel>
val currentBarAction: ActionMode = playbackSettings.barAction
private val _openPanel = MutableEvent<OpenPanel>()
val openPanel: Event<OpenPanel>
get() = _openPanel
private val _artistPlaybackPickerSong = MutableEvent<Song>()
/**
* Flag signaling to open a picker dialog in order to resolve an ambiguous choice when playing a
* [Song] from one of it's [Artist]s.
*
* @see playFromArtist
*/
val artistPickerSong: Event<Song>
get() = _artistPlaybackPickerSong
private val _genrePlaybackPickerSong = MutableEvent<Song>()
/**
* Flag signaling to open a picker dialog in order to resolve an ambiguous choice when playing a
* [Song] from one of it's [Genre]s.
*/
val genrePickerSong: Event<Song>
get() = _genrePlaybackPickerSong
/** The current action to show on the playback bar. */
val currentBarAction: ActionMode
get() = playbackSettings.barAction
private val _playbackDecision = MutableEvent<PlaybackDecision>()
val playbackDecision: Event<PlaybackDecision>
get() = _playbackDecision
/**
* The current audio session ID of the internal player. Null if no [InternalPlayer] is
@ -223,7 +207,7 @@ constructor(
playImpl(song, song.artists[0])
} else {
logD("$song has multiple artists, showing choice dialog")
_artistPlaybackPickerSong.put(song)
startPlaybackDecisionImpl(PlaybackDecision.PlayFromArtist(song))
}
}
@ -243,10 +227,19 @@ constructor(
playImpl(song, song.genres[0])
} else {
logD("$song has multiple genres, showing choice dialog")
_genrePlaybackPickerSong.put(song)
startPlaybackDecisionImpl(PlaybackDecision.PlayFromGenre(song))
}
}
private fun startPlaybackDecisionImpl(decision: PlaybackDecision) {
val existing = _playbackDecision.flow.value
if (existing != null) {
logD("Already handling decision $existing, ignoring $decision")
return
}
_playbackDecision.put(decision)
}
/**
* PLay a [Song] from one of it's [Playlist]s.
*
@ -560,11 +553,11 @@ constructor(
}
// --- UI CONTROL ---
fun openMain() = openImpl(Panel.Main)
fun openPlayback() = openImpl(Panel.Playback)
fun openQueue() = openImpl(Panel.Queue)
fun openMain() = openImpl(OpenPanel.Main)
fun openPlayback() = openImpl(OpenPanel.Playback)
fun openQueue() = openImpl(OpenPanel.Queue)
private fun openImpl(panel: Panel) {
private fun openImpl(panel: OpenPanel) {
val existing = openPanel.flow.value
if (existing != null) {
logD("Already opening $existing, ignoring opening $panel")
@ -617,8 +610,15 @@ constructor(
}
}
sealed interface Panel {
object Main : Panel
object Playback : Panel
object Queue : Panel
sealed interface OpenPanel {
object Main : OpenPanel
object Playback : OpenPanel
object Queue : OpenPanel
}
sealed interface PlaybackDecision {
val song: Song
class PlayFromArtist(override val song: Song) : PlaybackDecision
class PlayFromGenre(override val song: Song) : PlaybackDecision
}

View file

@ -32,6 +32,7 @@ import org.oxycblt.auxio.databinding.DialogMusicChoicesBinding
import org.oxycblt.auxio.list.ClickableListListener
import org.oxycblt.auxio.list.adapter.UpdateInstructions
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
import org.oxycblt.auxio.util.collectImmediately
@ -68,15 +69,9 @@ class PlayFromArtistDialog :
adapter = choiceAdapter
}
playbackModel.playbackDecision.consume()
pickerModel.setPickerSongUid(args.artistUid)
collectImmediately(pickerModel.currentPickerSong) {
if (it != null) {
choiceAdapter.update(it.artists, UpdateInstructions.Replace(0))
} else {
logD("No song to show choices for, navigating away")
findNavController().navigateUp()
}
}
collectImmediately(pickerModel.currentPickerSong, ::updateSong)
}
override fun onDestroyBinding(binding: DialogMusicChoicesBinding) {
@ -90,4 +85,13 @@ class PlayFromArtistDialog :
playbackModel.playFromArtist(song, item)
findNavController().navigateUp()
}
private fun updateSong(song: Song?) {
if (song == null) {
logD("No song to show choices for, navigating away")
findNavController().navigateUp()
return
}
choiceAdapter.update(song.artists, UpdateInstructions.Replace(0))
}
}

View file

@ -32,6 +32,7 @@ import org.oxycblt.auxio.databinding.DialogMusicChoicesBinding
import org.oxycblt.auxio.list.ClickableListListener
import org.oxycblt.auxio.list.adapter.UpdateInstructions
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
import org.oxycblt.auxio.util.collectImmediately
@ -68,15 +69,9 @@ class PlayFromGenreDialog :
adapter = choiceAdapter
}
playbackModel.playbackDecision.consume()
pickerModel.setPickerSongUid(args.genreUid)
collectImmediately(pickerModel.currentPickerSong) {
if (it != null) {
choiceAdapter.update(it.genres, UpdateInstructions.Replace(0))
} else {
logD("No song to show choices for, navigating away")
findNavController().navigateUp()
}
}
collectImmediately(pickerModel.currentPickerSong, ::updateSong)
}
override fun onDestroyBinding(binding: DialogMusicChoicesBinding) {
@ -90,4 +85,13 @@ class PlayFromGenreDialog :
playbackModel.playFromGenre(song, item)
findNavController().navigateUp()
}
private fun updateSong(song: Song?) {
if (song == null) {
logD("No song to show choices for, navigating away")
findNavController().navigateUp()
return
}
choiceAdapter.update(song.genres, UpdateInstructions.Replace(0))
}
}

View file

@ -52,6 +52,7 @@ import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.PlaylistDecision
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackDecision
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.util.collect
import org.oxycblt.auxio.util.collectImmediately
@ -145,6 +146,7 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
collect(musicModel.playlistDecision.flow, ::handleDecision)
collectImmediately(
playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback)
collect(playbackModel.playbackDecision.flow, ::handlePlaybackDecision)
collect(detailModel.toShow.flow, ::handleShow)
}
@ -260,34 +262,6 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
hideKeyboard()
}
private fun handleDecision(decision: PlaylistDecision?) {
if (decision == null) return
val directions =
when (decision) {
is PlaylistDecision.Rename -> {
logD("Renaming ${decision.playlist}")
SearchFragmentDirections.renamePlaylist(decision.playlist.uid)
}
is PlaylistDecision.Delete -> {
logD("Deleting ${decision.playlist}")
SearchFragmentDirections.deletePlaylist(decision.playlist.uid)
}
is PlaylistDecision.Add -> {
logD("Adding ${decision.songs.size} to a playlist")
SearchFragmentDirections.addToPlaylist(
decision.songs.map { it.uid }.toTypedArray())
}
is PlaylistDecision.New -> {
error("Unexpected decision $decision")
}
}
findNavController().navigateSafe(directions)
}
private fun updatePlayback(song: Song?, parent: MusicParent?, isPlaying: Boolean) {
searchAdapter.setPlaying(parent ?: song, isPlaying)
}
private fun handleMenu(pendingMenu: PendingMenu?) {
if (pendingMenu == null) return
val directions =
@ -326,6 +300,50 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
}
}
private fun handleDecision(decision: PlaylistDecision?) {
if (decision == null) return
val directions =
when (decision) {
is PlaylistDecision.Rename -> {
logD("Renaming ${decision.playlist}")
SearchFragmentDirections.renamePlaylist(decision.playlist.uid)
}
is PlaylistDecision.Delete -> {
logD("Deleting ${decision.playlist}")
SearchFragmentDirections.deletePlaylist(decision.playlist.uid)
}
is PlaylistDecision.Add -> {
logD("Adding ${decision.songs.size} to a playlist")
SearchFragmentDirections.addToPlaylist(
decision.songs.map { it.uid }.toTypedArray())
}
is PlaylistDecision.New -> {
error("Unexpected decision $decision")
}
}
findNavController().navigateSafe(directions)
}
private fun updatePlayback(song: Song?, parent: MusicParent?, isPlaying: Boolean) {
searchAdapter.setPlaying(parent ?: song, isPlaying)
}
private fun handlePlaybackDecision(decision: PlaybackDecision?) {
if (decision == null) return
val directions =
when (decision) {
is PlaybackDecision.PlayFromArtist -> {
logD("Launching play from artist dialog for $decision")
SearchFragmentDirections.playFromArtist(decision.song.uid)
}
is PlaybackDecision.PlayFromGenre -> {
logD("Launching play from artist dialog for $decision")
SearchFragmentDirections.playFromGenre(decision.song.uid)
}
}
findNavController().navigateSafe(directions)
}
/**
* Safely focus the keyboard on a particular [View].
*