Extend Popup actions

Extend the action menus to every music model.
This commit is contained in:
OxygenCobalt 2020-11-21 16:10:16 -07:00
parent d2350de12a
commit 13b80585d2
24 changed files with 291 additions and 115 deletions

View file

@ -59,9 +59,9 @@ class MainFragment : Fragment() {
)
val navController = (
childFragmentManager.findFragmentById(R.id.explore_nav_host)
as NavHostFragment?
)?.findNavController()
childFragmentManager.findFragmentById(R.id.explore_nav_host)
as NavHostFragment?
)?.findNavController()
// --- UI SETUP ---

View file

@ -14,4 +14,7 @@ interface PlaybackStateDAO {
@Query("DELETE FROM playback_state_table")
fun clear()
@Query("SELECT * FROM playback_state_table ORDER BY id DESC LIMIT 1")
fun getRecent(): PlaybackState?
}

View file

@ -18,8 +18,11 @@ interface QueueDAO {
}
}
@Query("SELECT * FROM queue_table")
fun getAll(): List<QueueItem>
@Query("SELECT * FROM queue_table WHERE is_user_queue == 1")
fun getUserQueue(): List<QueueItem>
@Query("SELECT * FROM queue_table WHERE is_user_queue == 0")
fun getQueue(): List<QueueItem>
@Query("DELETE FROM queue_table")
fun clear()

View file

@ -22,7 +22,6 @@ import org.oxycblt.auxio.ui.setupAlbumSongActions
class AlbumDetailFragment : DetailFragment() {
private val args: AlbumDetailFragmentArgs by navArgs()
private val detailModel: DetailViewModel by activityViewModels()
private val playbackModel: PlaybackViewModel by activityViewModels()
override fun onCreateView(
@ -45,10 +44,8 @@ class AlbumDetailFragment : DetailFragment() {
}
val songAdapter = DetailSongAdapter(
{
playbackModel.playSong(it, PlaybackMode.IN_ALBUM)
},
{ data, view ->
doOnClick = { playbackModel.playSong(it, PlaybackMode.IN_ALBUM) },
doOnLongClick = { data, view ->
PopupMenu(requireContext(), view).setupAlbumSongActions(
data, requireContext(), detailModel, playbackModel
)
@ -76,6 +73,10 @@ class AlbumDetailFragment : DetailFragment() {
R.id.action_play -> playbackModel.playAlbum(
detailModel.currentAlbum.value!!, false
)
R.id.action_queue_add -> playbackModel.addToUserQueue(
detailModel.currentAlbum.value!!.songs
)
}
true

View file

@ -5,6 +5,7 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.PopupMenu
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
@ -15,10 +16,10 @@ import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.applyDivider
import org.oxycblt.auxio.ui.disable
import org.oxycblt.auxio.ui.setupAlbumActions
class ArtistDetailFragment : DetailFragment() {
private val args: ArtistDetailFragmentArgs by navArgs()
private val detailModel: DetailViewModel by activityViewModels()
private val playbackModel: PlaybackViewModel by activityViewModels()
override fun onCreateView(
@ -40,15 +41,22 @@ class ArtistDetailFragment : DetailFragment() {
)
}
val albumAdapter = DetailAlbumAdapter {
if (!detailModel.isNavigating) {
detailModel.updateNavigationStatus(true)
val albumAdapter = DetailAlbumAdapter(
doOnClick = {
if (!detailModel.isNavigating) {
detailModel.updateNavigationStatus(true)
findNavController().navigate(
ArtistDetailFragmentDirections.actionShowAlbum(it.id, false)
findNavController().navigate(
ArtistDetailFragmentDirections.actionShowAlbum(it.id, false)
)
}
},
doOnLongClick = { data, view ->
PopupMenu(requireContext(), view).setupAlbumActions(
data, requireContext(), playbackModel
)
}
}
)
// --- UI SETUP ---
@ -106,10 +114,4 @@ class ArtistDetailFragment : DetailFragment() {
return binding.root
}
override fun onResume() {
super.onResume()
detailModel.updateNavigationStatus(false)
}
}

View file

@ -4,14 +4,18 @@ import android.os.Bundle
import android.view.View
import androidx.activity.OnBackPressedCallback
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
/**
* A Base [Fragment] implementing a [OnBackPressedCallback] so that Auxio will navigate upwards
* instead of out of the app if a Detail Fragment is currently open.
* instead of out of the app if a Detail Fragment is currently open. Also carries the
* multi-navigation fix.
* @author OxygenCobalt
*/
abstract class DetailFragment : Fragment() {
protected val detailModel: DetailViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, callback)
}
@ -20,6 +24,7 @@ abstract class DetailFragment : Fragment() {
super.onResume()
callback.isEnabled = true
detailModel.updateNavigationStatus(false)
}
override fun onPause() {

View file

@ -5,6 +5,7 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.PopupMenu
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
@ -15,11 +16,11 @@ import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.applyDivider
import org.oxycblt.auxio.ui.disable
import org.oxycblt.auxio.ui.setupArtistActions
class GenreDetailFragment : DetailFragment() {
private val args: GenreDetailFragmentArgs by navArgs()
private val detailModel: DetailViewModel by activityViewModels()
private val playbackModel: PlaybackViewModel by activityViewModels()
override fun onCreateView(
@ -41,15 +42,22 @@ class GenreDetailFragment : DetailFragment() {
)
}
val artistAdapter = DetailArtistAdapter {
if (!detailModel.isNavigating) {
detailModel.updateNavigationStatus(true)
val artistAdapter = DetailArtistAdapter(
doOnClick = {
if (!detailModel.isNavigating) {
detailModel.updateNavigationStatus(true)
findNavController().navigate(
GenreDetailFragmentDirections.actionShowArtist(it.id)
findNavController().navigate(
GenreDetailFragmentDirections.actionShowArtist(it.id)
)
}
},
doOnLongClick = { data, view ->
PopupMenu(requireContext(), view).setupArtistActions(
data, requireContext(), playbackModel
)
}
}
)
// --- UI SETUP ---
@ -106,10 +114,4 @@ class GenreDetailFragment : DetailFragment() {
return binding.root
}
override fun onResume() {
super.onResume()
detailModel.updateNavigationStatus(false)
}
}

View file

@ -1,6 +1,7 @@
package org.oxycblt.auxio.detail.adapters
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import org.oxycblt.auxio.databinding.ItemArtistAlbumBinding
@ -9,7 +10,8 @@ import org.oxycblt.auxio.recycler.DiffCallback
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
class DetailAlbumAdapter(
private val doOnClick: (data: Album) -> Unit
private val doOnClick: (data: Album) -> Unit,
private val doOnLongClick: (data: Album, view: View) -> Unit
) : ListAdapter<Album, DetailAlbumAdapter.ViewHolder>(DiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
@ -25,7 +27,7 @@ class DetailAlbumAdapter(
// Generic ViewHolder for a detail album
inner class ViewHolder(
private val binding: ItemArtistAlbumBinding,
) : BaseViewHolder<Album>(binding, doOnClick, null) {
) : BaseViewHolder<Album>(binding, doOnClick, doOnLongClick) {
override fun onBind(data: Album) {
binding.album = data

View file

@ -1,6 +1,7 @@
package org.oxycblt.auxio.detail.adapters
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import org.oxycblt.auxio.databinding.ItemGenreArtistBinding
@ -9,7 +10,8 @@ import org.oxycblt.auxio.recycler.DiffCallback
import org.oxycblt.auxio.recycler.viewholders.BaseViewHolder
class DetailArtistAdapter(
private val doOnClick: (data: Artist) -> Unit
private val doOnClick: (data: Artist) -> Unit,
private val doOnLongClick: (data: Artist, view: View) -> Unit
) : ListAdapter<Artist, DetailArtistAdapter.ViewHolder>(DiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
@ -25,7 +27,7 @@ class DetailArtistAdapter(
// Generic ViewHolder for an album
inner class ViewHolder(
private val binding: ItemGenreArtistBinding
) : BaseViewHolder<Artist>(binding, doOnClick, null) {
) : BaseViewHolder<Artist>(binding, doOnClick, doOnLongClick) {
override fun onBind(data: Artist) {
binding.artist = data

View file

@ -30,6 +30,9 @@ import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.ui.applyColor
import org.oxycblt.auxio.ui.applyDivider
import org.oxycblt.auxio.ui.resolveAttr
import org.oxycblt.auxio.ui.setupAlbumActions
import org.oxycblt.auxio.ui.setupArtistActions
import org.oxycblt.auxio.ui.setupGenreActions
import org.oxycblt.auxio.ui.setupSongActions
// A Fragment to show all the music in the Library.
@ -47,21 +50,15 @@ class LibraryFragment : Fragment(), SearchView.OnQueryTextListener {
val musicStore = MusicStore.getInstance()
val libraryAdapter = LibraryAdapter(libraryModel.showMode.value!!) {
navToItem(it)
}
val libraryAdapter = LibraryAdapter(
libraryModel.showMode.value!!,
doOnClick = { navToItem(it) },
doOnLongClick = { data, view -> showActionsForItem(data, view) }
)
val searchAdapter = SearchAdapter(
{
navToItem(it)
},
{ data, view ->
if (data is Song) {
PopupMenu(requireContext(), view).setupSongActions(
data, requireContext(), playbackModel
)
}
}
doOnClick = { navToItem(it) },
doOnLongClick = { data, view -> showActionsForItem(data, view) }
)
// --- UI SETUP ---
@ -175,6 +172,19 @@ class LibraryFragment : Fragment(), SearchView.OnQueryTextListener {
return false
}
private fun showActionsForItem(data: BaseModel, view: View) {
val menu = PopupMenu(requireContext(), view)
when (data) {
is Song -> menu.setupSongActions(data, requireContext(), playbackModel)
is Album -> menu.setupAlbumActions(data, requireContext(), playbackModel)
is Artist -> menu.setupArtistActions(data, requireContext(), playbackModel)
is Genre -> menu.setupGenreActions(data, requireContext(), playbackModel)
else -> {
}
}
}
private fun navToItem(baseModel: BaseModel) {
// If the item is a song [That was selected through search], then update the playback
// to that song instead of doing any navigation

View file

@ -22,7 +22,7 @@ class LibraryViewModel : ViewModel() {
val searchHasFocus: Boolean get() = mSearchHasFocus
// TODO: Move these to prefs when they're added
private val mShowMode = MutableLiveData(ShowMode.SHOW_ARTISTS)
private val mShowMode = MutableLiveData(ShowMode.SHOW_GENRES)
val showMode: LiveData<ShowMode> get() = mShowMode
private val mSortMode = MutableLiveData(SortMode.ALPHA_DOWN)

View file

@ -1,5 +1,6 @@
package org.oxycblt.auxio.library.adapters
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.music.Album
@ -11,12 +12,11 @@ import org.oxycblt.auxio.recycler.viewholders.AlbumViewHolder
import org.oxycblt.auxio.recycler.viewholders.ArtistViewHolder
import org.oxycblt.auxio.recycler.viewholders.GenreViewHolder
// A ListAdapter that can contain three different types of ViewHolders depending
// the ShowMode given.
// It cannot display multiple ViewHolders *at once* however. That's what SearchAdapter is for.
// The primary RecyclerView adapter for the library. Displays genres, artists, and albums.
class LibraryAdapter(
private val showMode: ShowMode,
private val doOnClick: (data: BaseModel) -> Unit
private val doOnClick: (data: BaseModel) -> Unit,
private val doOnLongClick: (data: BaseModel, view: View) -> Unit
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var data: List<BaseModel>
@ -37,10 +37,11 @@ class LibraryAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
// Return a different View Holder depending on the show type
return when (showMode) {
ShowMode.SHOW_GENRES -> GenreViewHolder.from(parent.context, doOnClick)
ShowMode.SHOW_ARTISTS -> ArtistViewHolder.from(parent.context, doOnClick)
ShowMode.SHOW_ALBUMS -> AlbumViewHolder.from(parent.context, doOnClick)
else -> ArtistViewHolder.from(parent.context, doOnClick)
ShowMode.SHOW_GENRES -> GenreViewHolder.from(parent.context, doOnClick, doOnLongClick)
ShowMode.SHOW_ARTISTS -> ArtistViewHolder.from(parent.context, doOnClick, doOnLongClick)
ShowMode.SHOW_ALBUMS -> AlbumViewHolder.from(parent.context, doOnClick, doOnLongClick)
else -> error("Bad ShowMode given.")
}
}

View file

@ -34,14 +34,22 @@ class SearchAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
GenreViewHolder.ITEM_TYPE -> GenreViewHolder.from(parent.context, doOnClick)
ArtistViewHolder.ITEM_TYPE -> ArtistViewHolder.from(parent.context, doOnClick)
AlbumViewHolder.ITEM_TYPE -> AlbumViewHolder.from(parent.context, doOnClick)
SongViewHolder.ITEM_TYPE -> SongViewHolder.from(
parent.context,
doOnClick,
doOnLongClick
GenreViewHolder.ITEM_TYPE -> GenreViewHolder.from(
parent.context, doOnClick, doOnLongClick
)
ArtistViewHolder.ITEM_TYPE -> ArtistViewHolder.from(
parent.context, doOnClick, doOnLongClick
)
AlbumViewHolder.ITEM_TYPE -> AlbumViewHolder.from(
parent.context, doOnClick, doOnLongClick
)
SongViewHolder.ITEM_TYPE -> SongViewHolder.from(
parent.context, doOnClick, doOnLongClick
)
HeaderViewHolder.ITEM_TYPE -> HeaderViewHolder.from(parent.context)
else -> error("Someone messed with the ViewHolder item types.")

View file

@ -86,7 +86,6 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
// Make marquee scroll work
// TODO: Add nav here as well
binding.playbackSong.isSelected = true
binding.playbackSeekBar.setOnSeekBarChangeListener(this)
// --- VIEWMODEL SETUP --
@ -127,6 +126,8 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
} else {
binding.playbackShuffle.imageTintList = controlColor
}
Log.d(this::class.simpleName, "Shuffle swap")
}
playbackModel.loopMode.observe(viewLifecycleOwner) {

View file

@ -226,6 +226,10 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback {
playbackManager.addToUserQueue(song)
}
fun addToUserQueue(songs: List<Song>) {
playbackManager.addToUserQueue(songs)
}
// --- STATUS FUNCTIONS ---
// Flip the playing status.

View file

@ -141,7 +141,8 @@ class PlaybackStateManager private constructor() {
mQueue = song.album.songs
}
else -> {}
else -> {
}
}
mMode = mode
@ -254,7 +255,6 @@ class PlaybackStateManager private constructor() {
}
updatePlayback(mQueue[mIndex])
forceQueueUpdate()
}
}
@ -304,6 +304,12 @@ class PlaybackStateManager private constructor() {
forceUserQueueUpdate()
}
fun addToUserQueue(songs: List<Song>) {
mUserQueue.addAll(songs)
forceUserQueueUpdate()
}
fun removeUserQueueItem(index: Int) {
Log.d(this::class.simpleName, "Removing item ${mUserQueue[index].name}.")
@ -426,8 +432,6 @@ class PlaybackStateManager private constructor() {
val start = System.currentTimeMillis()
Log.d(this::class.simpleName, packQueue().size.toString())
withContext(Dispatchers.IO) {
val playbackState = packToPlaybackState()
val queueItems = packQueue()
@ -450,13 +454,16 @@ class PlaybackStateManager private constructor() {
val start = System.currentTimeMillis()
val states: List<PlaybackState>
val state: PlaybackState?
val queueItems: List<QueueItem>
val userQueueItems: List<QueueItem>
withContext(Dispatchers.IO) {
val database = AuxioDatabase.getInstance(context)
states = database.playbackStateDAO.getAll()
queueItems = database.queueDAO.getAll()
state = database.playbackStateDAO.getRecent()
queueItems = database.queueDAO.getQueue()
userQueueItems = database.queueDAO.getUserQueue()
database.playbackStateDAO.clear()
database.queueDAO.clear()
@ -466,7 +473,7 @@ class PlaybackStateManager private constructor() {
Log.d(this::class.simpleName, "Load finished in ${loadTime}ms")
if (states.isEmpty()) {
if (state == null) {
Log.d(this::class.simpleName, "Nothing here. Not restoring.")
mIsRestored = true
@ -474,13 +481,13 @@ class PlaybackStateManager private constructor() {
return
}
Log.d(this::class.simpleName, "Old state found, ${states[0]}")
Log.d(this::class.simpleName, "Old state found, $state")
unpackFromPlaybackState(states[0])
unpackFromPlaybackState(state)
Log.d(this::class.simpleName, "Found queue of size ${queueItems.size}")
unpackQueue(queueItems)
unpackQueues(queueItems, userQueueItems)
mSong?.let {
mIndex = mQueue.indexOf(mSong)
@ -543,18 +550,22 @@ class PlaybackStateManager private constructor() {
}
}
private fun unpackQueue(queueItems: List<QueueItem>) {
private fun unpackQueues(queueItems: List<QueueItem>, userQueueItems: List<QueueItem>) {
val musicStore = MusicStore.getInstance()
queueItems.forEach { item ->
// Traverse albums and then album songs instead of just the songs, as its faster.
musicStore.albums.find { it.id == item.albumId }?.songs?.find { it.id == item.songId }?.let {
if (item.isUserQueue) {
mUserQueue.add(it)
} else {
musicStore.albums.find { it.id == item.albumId }
?.songs?.find { it.id == item.songId }?.let {
mQueue.add(it)
}
}
}
userQueueItems.forEach { item ->
musicStore.albums.find { it.id == item.albumId }
?.songs?.find { it.id == item.songId }?.let {
mUserQueue.add(it)
}
}
forceQueueUpdate()

View file

@ -19,8 +19,9 @@ import org.oxycblt.auxio.music.Song
class GenreViewHolder private constructor(
private val binding: ItemGenreBinding,
doOnClick: (Genre) -> Unit
) : BaseViewHolder<Genre>(binding, doOnClick, null) {
doOnClick: (Genre) -> Unit,
doOnLongClick: (data: Genre, view: View) -> Unit
) : BaseViewHolder<Genre>(binding, doOnClick, doOnLongClick) {
override fun onBind(data: Genre) {
binding.genre = data
@ -30,10 +31,14 @@ class GenreViewHolder private constructor(
companion object {
const val ITEM_TYPE = 0xA010
fun from(context: Context, doOnClick: (Genre) -> Unit): GenreViewHolder {
fun from(
context: Context,
doOnClick: (Genre) -> Unit,
doOnLongClick: (data: Genre, view: View) -> Unit
): GenreViewHolder {
return GenreViewHolder(
ItemGenreBinding.inflate(LayoutInflater.from(context)),
doOnClick
doOnClick, doOnLongClick
)
}
}
@ -42,7 +47,8 @@ class GenreViewHolder private constructor(
class ArtistViewHolder private constructor(
private val binding: ItemArtistBinding,
doOnClick: (Artist) -> Unit,
) : BaseViewHolder<Artist>(binding, doOnClick, null) {
doOnLongClick: (data: Artist, view: View) -> Unit
) : BaseViewHolder<Artist>(binding, doOnClick, doOnLongClick) {
override fun onBind(data: Artist) {
binding.artist = data
@ -52,10 +58,14 @@ class ArtistViewHolder private constructor(
companion object {
const val ITEM_TYPE = 0xA011
fun from(context: Context, doOnClick: (Artist) -> Unit): ArtistViewHolder {
fun from(
context: Context,
doOnClick: (Artist) -> Unit,
doOnLongClick: (data: Artist, view: View) -> Unit
): ArtistViewHolder {
return ArtistViewHolder(
ItemArtistBinding.inflate(LayoutInflater.from(context)),
doOnClick
doOnClick, doOnLongClick
)
}
}
@ -63,8 +73,9 @@ class ArtistViewHolder private constructor(
class AlbumViewHolder private constructor(
private val binding: ItemAlbumBinding,
doOnClick: (data: Album) -> Unit
) : BaseViewHolder<Album>(binding, doOnClick, null) {
doOnClick: (data: Album) -> Unit,
doOnLongClick: (data: Album, view: View) -> Unit
) : BaseViewHolder<Album>(binding, doOnClick, doOnLongClick) {
override fun onBind(data: Album) {
binding.album = data
@ -74,10 +85,14 @@ class AlbumViewHolder private constructor(
companion object {
const val ITEM_TYPE = 0xA012
fun from(context: Context, doOnClick: (data: Album) -> Unit): AlbumViewHolder {
fun from(
context: Context,
doOnClick: (data: Album) -> Unit,
doOnLongClick: (data: Album, view: View) -> Unit
): AlbumViewHolder {
return AlbumViewHolder(
ItemAlbumBinding.inflate(LayoutInflater.from(context)),
doOnClick,
doOnClick, doOnLongClick
)
}
}

View file

@ -43,10 +43,8 @@ class SongsFragment : Fragment() {
binding.songRecycler.apply {
adapter = SongAdapter(
musicStore.songs,
{
playbackModel.playSong(it, PlaybackMode.ALL_SONGS)
},
{ data, view ->
doOnClick = { playbackModel.playSong(it, PlaybackMode.ALL_SONGS) },
doOnLongClick = { data, view ->
PopupMenu(requireContext(), view).setupSongActions(
data, requireContext(), playbackModel
)

View file

@ -14,6 +14,9 @@ import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.R
import org.oxycblt.auxio.detail.DetailViewModel
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.state.PlaybackMode
@ -64,8 +67,8 @@ fun PopupMenu.setupSongActions(song: Song, context: Context, playbackModel: Play
setOnMenuItemClickListener {
when (it.itemId) {
R.id.action_queue_add -> {
doUserQueueAdd(context, song, playbackModel)
playbackModel.addToUserQueue(song)
context.getString(R.string.label_queue_added).createToast(context)
true
}
@ -95,7 +98,8 @@ fun PopupMenu.setupAlbumSongActions(
setOnMenuItemClickListener {
when (it.itemId) {
R.id.action_queue_add -> {
doUserQueueAdd(context, song, playbackModel)
playbackModel.addToUserQueue(song)
context.getString(R.string.label_queue_added).createToast(context)
true
}
@ -116,12 +120,95 @@ fun PopupMenu.setupAlbumSongActions(
show()
}
private fun doUserQueueAdd(context: Context, song: Song, playbackModel: PlaybackViewModel) {
// If the song was already added to the user queue, then don't add it again.
// This is just to prevent a bug with DiffCallback that creates strange
// behavior when duplicate user queue items are added.
// FIXME: Fix the duplicate item DiffCallback issue
playbackModel.addToUserQueue(song)
fun PopupMenu.setupAlbumActions(
album: Album,
context: Context,
playbackModel: PlaybackViewModel
) {
inflate(R.menu.menu_album_actions)
setOnMenuItemClickListener {
when (it.itemId) {
R.id.action_queue_add -> {
playbackModel.addToUserQueue(album.songs)
context.getString(R.string.label_queue_added).createToast(context)
context.getString(R.string.label_queue_added).createToast(context)
true
}
R.id.action_play -> {
playbackModel.playAlbum(album, false)
true
}
R.id.action_shuffle -> {
playbackModel.playAlbum(album, true)
true
}
else -> false
}
}
show()
}
fun PopupMenu.setupArtistActions(
artist: Artist,
context: Context,
playbackModel: PlaybackViewModel
) {
inflate(R.menu.menu_detail)
setOnMenuItemClickListener {
when (it.itemId) {
R.id.action_queue_add -> {
playbackModel.addToUserQueue(artist.songs)
context.getString(R.string.label_queue_added).createToast(context)
true
}
R.id.action_play -> {
playbackModel.playArtist(artist, false)
true
}
R.id.action_shuffle -> {
playbackModel.playArtist(artist, true)
true
}
else -> false
}
}
show()
}
fun PopupMenu.setupGenreActions(
genre: Genre,
context: Context,
playbackModel: PlaybackViewModel
) {
inflate(R.menu.menu_detail)
setOnMenuItemClickListener {
when (it.itemId) {
R.id.action_queue_add -> {
playbackModel.addToUserQueue(genre.songs)
context.getString(R.string.label_queue_added).createToast(context)
true
}
R.id.action_play -> {
playbackModel.playGenre(genre, false)
true
}
R.id.action_shuffle -> {
playbackModel.playGenre(genre, true)
true
}
else -> false
}
}
show()
}

View file

@ -30,8 +30,8 @@
android:layout_height="?android:attr/actionBarSize"
android:background="?android:attr/windowBackground"
android:elevation="@dimen/elevation_normal"
app:menu="@menu/menu_detail"
app:popupTheme="@style/AppThemeOverlay.Popup"
app:menu="@menu/menu_album_actions"
app:titleTextAppearance="@style/TextAppearance.Toolbar.Header"
app:navigationIcon="@drawable/ic_back"
app:title="@string/title_library_fragment" />

View file

@ -30,6 +30,7 @@
android:layout_height="?android:attr/actionBarSize"
android:background="?android:attr/windowBackground"
android:elevation="@dimen/elevation_normal"
app:popupTheme="@style/AppThemeOverlay.Popup"
app:menu="@menu/menu_detail"
app:titleTextAppearance="@style/TextAppearance.Toolbar.Header"
app:navigationIcon="@drawable/ic_back"

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_play"
android:title="@string/label_play"
android:icon="@drawable/ic_play"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_shuffle"
android:icon="@drawable/ic_shuffle"
android:title="@string/label_shuffle"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_queue_add"
android:icon="@drawable/ic_queue_add"
app:showAsAction="never"
android:title="@string/label_queue_add" />
</menu>

View file

@ -5,5 +5,5 @@
android:id="@+id/action_queue"
android:icon="@drawable/ic_queue"
android:title="@string/label_queue"
app:showAsAction="always" />
app:showAsAction="ifRoom" />
</menu>

View file

@ -28,6 +28,7 @@
<string name="label_play_artist">Play from artist</string>
<string name="label_play_album">Play from album</string>
<string name="label_go_artist">Go to artist</string>
<string name="label_go_album">Go to album</string>
<string name="label_queue">Queue</string>
<string name="label_queue_add">Add to queue</string>
<string name="label_queue_added">Added to queue</string>