playback: add playlist support

Add playlist support to the playback code.
This commit is contained in:
Alexander Capehart 2023-03-23 16:07:56 -06:00
parent 52e0620149
commit f388e492aa
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
5 changed files with 66 additions and 30 deletions

View file

@ -3,17 +3,16 @@
## dev
#### What's New
- Added support for `COMPILATION` and `ITUNESCOMPILATION` flags.
- Added support for `COMPILATION` and `ITUNESCOMPILATION` flags
#### What's Improved
- Accept `REPLAYGAIN_*` adjustment information on OPUS files alongside
`R128_*` adjustments
- List updates are now consistent across the app
- Fixed jarring header update in detail view
- Search view now trims search queries
- Searching now ignores punctuation and trailing whitespace
- Audio effect (equalizer) session is now broadcast when playing/pausing
rather than on start/stop
- Searching now ignores punctuation
- Numeric names are now logically sorted (i.e 7 before 15)
#### What's Fixed

View file

@ -26,7 +26,6 @@ import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.ConcatAdapter
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.transition.MaterialSharedAxis
import dagger.hilt.android.AndroidEntryPoint
import org.oxycblt.auxio.R
@ -114,16 +113,15 @@ class PlaylistDetailFragment :
return true
}
// TODO: Handle
val currentPlaylist = unlikelyToBeNull(detailModel.currentPlaylist.value)
return when (item.itemId) {
R.id.action_play_next -> {
// playbackModel.playNext(currentPlaylist)
playbackModel.playNext(currentPlaylist)
requireContext().showToast(R.string.lng_queue_added)
true
}
R.id.action_queue_add -> {
// playbackModel.addToQueue(currentPlaylist)
playbackModel.addToQueue(currentPlaylist)
requireContext().showToast(R.string.lng_queue_added)
true
}
@ -131,12 +129,8 @@ class PlaylistDetailFragment :
}
}
override fun onClick(item: Song, viewHolder: RecyclerView.ViewHolder) {
// TODO: Handle
}
override fun onRealClick(item: Song) {
// TODO: Handle
playbackModel.playFromPlaylist(item, unlikelyToBeNull(detailModel.currentPlaylist.value))
}
override fun onOpenMenu(item: Song, anchor: View) {
@ -145,11 +139,11 @@ class PlaylistDetailFragment :
override fun onPlay() {
// TODO: Handle
// playbackModel.play(unlikelyToBeNull(detailModel.currentPlaylist.value))
playbackModel.play(unlikelyToBeNull(detailModel.currentPlaylist.value))
}
override fun onShuffle() {
// playbackModel.shuffle(unlikelyToBeNull(detailModel.currentPlaylist.value))
playbackModel.shuffle(unlikelyToBeNull(detailModel.currentPlaylist.value))
}
override fun onOpenSortMenu(anchor: View) {

View file

@ -58,7 +58,7 @@ abstract class ListFragment<in T : Music, VB : ViewBinding> :
*/
abstract fun onRealClick(item: T)
override fun onClick(item: T, viewHolder: RecyclerView.ViewHolder) {
final override fun onClick(item: T, viewHolder: RecyclerView.ViewHolder) {
if (selectionModel.selected.value.isNotEmpty()) {
// Map clicking an item to selecting an item when items are already selected.
selectionModel.select(item)
@ -68,7 +68,7 @@ abstract class ListFragment<in T : Music, VB : ViewBinding> :
}
}
override fun onSelect(item: T) {
final override fun onSelect(item: T) {
selectionModel.select(item)
}
@ -222,26 +222,26 @@ abstract class ListFragment<in T : Music, VB : ViewBinding> :
*
* @param anchor The [View] to anchor the menu to.
* @param menuRes The resource of the menu to load.
* @param genre The [Playlist] to create the menu for.
* @param playlist The [Playlist] to create the menu for.
*/
protected fun openMusicMenu(anchor: View, @MenuRes menuRes: Int, genre: Playlist) {
logD("Launching new genre menu: ${genre.rawName}")
protected fun openMusicMenu(anchor: View, @MenuRes menuRes: Int, playlist: Playlist) {
logD("Launching new playlist menu: ${playlist.rawName}")
openMusicMenuImpl(anchor, menuRes) {
when (it.itemId) {
R.id.action_play -> {
// playbackModel.play(genre)
playbackModel.play(playlist)
}
R.id.action_shuffle -> {
// playbackModel.shuffle(genre)
playbackModel.shuffle(playlist)
}
R.id.action_play_next -> {
// playbackModel.playNext(genre)
// requireContext().showToast(R.string.lng_queue_added)
playbackModel.playNext(playlist)
requireContext().showToast(R.string.lng_queue_added)
}
R.id.action_queue_add -> {
// playbackModel.addToQueue(genre)
// requireContext().showToast(R.string.lng_queue_added)
playbackModel.addToQueue(playlist)
requireContext().showToast(R.string.lng_queue_added)
}
else -> {
error("Unexpected menu item selected")

View file

@ -168,6 +168,7 @@ constructor(
* - If [MusicMode.ALBUMS], the [Song] is played from it's [Album].
* - If [MusicMode.ARTISTS], the [Song] is played from one of it's [Artist]s.
* - If [MusicMode.GENRES], the [Song] is played from one of it's [Genre]s.
* [MusicMode.PLAYLISTS] is disallowed here.
*
* @param song The [Song] to play.
* @param playbackMode The [MusicMode] to play from.
@ -200,7 +201,7 @@ constructor(
}
/**
* PLay a [Song] from one of it's [Genre]s.
* Play a [Song] from one of it's [Genre]s.
*
* @param song The [Song] to play.
* @param genre The [Genre] to play from. Must be linked to the [Song]. If null, the user will
@ -216,6 +217,16 @@ constructor(
}
}
/**
* PLay a [Song] from one of it's [Playlist]s.
*
* @param song The [Song] to play.
* @param playlist The [Playlist] to play from. Must be linked to the [Song].
*/
fun playFromPlaylist(song: Song, playlist: Playlist) {
playImpl(song, playlist)
}
/**
* Play an [Album].
*
@ -237,6 +248,13 @@ constructor(
*/
fun play(genre: Genre) = playImpl(null, genre, false)
/**
* Play a [Playlist].
*
* @param playlist The [Playlist] to play.
*/
fun play(playlist: Playlist) = playImpl(null, playlist, false)
/**
* Play a [Music] selection.
*
@ -260,12 +278,19 @@ constructor(
fun shuffle(artist: Artist) = playImpl(null, artist, true)
/**
* Shuffle an [Genre].
* Shuffle a [Genre].
*
* @param genre The [Genre] to shuffle.
*/
fun shuffle(genre: Genre) = playImpl(null, genre, true)
/**
* Shuffle a [Playlist].
*
* @param playlist The [Playlist] to shuffle.
*/
fun shuffle(playlist: Playlist) = playImpl(null, playlist, true)
/**
* Shuffle a [Music] selection.
*
@ -292,7 +317,7 @@ constructor(
null -> musicSettings.songSort
}
val songs = parent?.songs ?: deviceLibrary.songs
val queue = sort?.songs(songs) ?: songs
val queue = sort.songs(songs)
playbackManager.play(song, parent, queue, shuffled)
}
@ -365,6 +390,15 @@ constructor(
playbackManager.playNext(musicSettings.genreSongSort.songs(genre.songs))
}
/**
* Add a [Playlist] to the top of the queue.
*
* @param playlist The [Playlist] to add.
*/
fun playNext(playlist: Playlist) {
playbackManager.playNext(musicSettings.playlistSongSort.songs(playlist.songs))
}
/**
* Add a selection to the top of the queue.
*
@ -410,6 +444,15 @@ constructor(
playbackManager.addToQueue(musicSettings.genreSongSort.songs(genre.songs))
}
/**
* Add a [Playlist] to the end of the queue.
*
* @param playlist The [Playlist] to add.
*/
fun addToQueue(playlist: Playlist) {
playbackManager.addToQueue(musicSettings.playlistSongSort.songs(playlist.songs))
}
/**
* Add a selection to the end of the queue.
*
@ -494,7 +537,7 @@ constructor(
is Album -> musicSettings.albumSongSort.songs(it.songs)
is Artist -> musicSettings.artistSongSort.songs(it.songs)
is Genre -> musicSettings.genreSongSort.songs(it.songs)
is Playlist -> musicSettings.playlistSongSort?.songs(it.songs) ?: it.songs
is Playlist -> musicSettings.playlistSongSort.songs(it.songs)
}
}
}

View file

@ -50,7 +50,7 @@ open class FakeMusicSettings : MusicSettings {
set(_) = throw NotImplementedError()
override var playlistSort: Sort
get() = throw NotImplementedError()
set(value) = throw NotImplementedError()
set(_) = throw NotImplementedError()
override var albumSongSort: Sort
get() = throw NotImplementedError()
set(_) = throw NotImplementedError()