menu: move item logic from listfragment
Move menu action logic from ListFragment into corresponding MenuFragments.
This commit is contained in:
parent
d6a20fedb3
commit
39b1fd1057
4 changed files with 112 additions and 294 deletions
|
@ -144,7 +144,7 @@ class AlbumListFragment :
|
|||
}
|
||||
|
||||
override fun onOpenMenu(item: Album, anchor: View) {
|
||||
openMusicMenu(anchor, R.menu.item_album, item)
|
||||
menuModel.openMenu(R.menu.item_album, item)
|
||||
}
|
||||
|
||||
private fun updateAlbums(albums: List<Album>) {
|
||||
|
|
|
@ -24,19 +24,10 @@ import androidx.appcompat.widget.PopupMenu
|
|||
import androidx.core.view.MenuCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.detail.DetailViewModel
|
||||
import org.oxycblt.auxio.list.selection.SelectionFragment
|
||||
import org.oxycblt.auxio.music.Album
|
||||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.Playlist
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.share
|
||||
import org.oxycblt.auxio.util.showToast
|
||||
|
||||
/**
|
||||
* A Fragment containing a selectable list.
|
||||
|
@ -76,281 +67,6 @@ abstract class ListFragment<in T : Music, VB : ViewBinding> :
|
|||
selectionModel.select(item)
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a menu in the context of a [Song]. This menu will be managed by the Fragment and closed
|
||||
* when the view is destroyed. If a menu is already opened, this call is ignored.
|
||||
*
|
||||
* @param anchor The [View] to anchor the menu to.
|
||||
* @param menuRes The resource of the menu to load.
|
||||
* @param song The [Song] to create the menu for.
|
||||
*/
|
||||
protected fun openMusicMenu(anchor: View, @MenuRes menuRes: Int, song: Song) {
|
||||
logD("Launching new song menu: ${song.name}")
|
||||
|
||||
openMenu(anchor, menuRes) {
|
||||
setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
R.id.action_play_next -> {
|
||||
playbackModel.playNext(song)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
true
|
||||
}
|
||||
R.id.action_queue_add -> {
|
||||
playbackModel.addToQueue(song)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
true
|
||||
}
|
||||
R.id.action_go_artist -> {
|
||||
detailModel.showArtist(song)
|
||||
true
|
||||
}
|
||||
R.id.action_go_album -> {
|
||||
detailModel.showAlbum(song.album)
|
||||
true
|
||||
}
|
||||
R.id.action_share -> {
|
||||
requireContext().share(song)
|
||||
true
|
||||
}
|
||||
R.id.action_playlist_add -> {
|
||||
musicModel.addToPlaylist(song)
|
||||
true
|
||||
}
|
||||
R.id.action_song_detail -> {
|
||||
detailModel.showSong(song)
|
||||
true
|
||||
}
|
||||
else -> {
|
||||
logW("Unexpected menu item selected")
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a menu in the context of a [Album]. This menu will be managed by the Fragment and
|
||||
* closed when the view is destroyed. If a menu is already opened, this call is ignored.
|
||||
*
|
||||
* @param anchor The [View] to anchor the menu to.
|
||||
* @param menuRes The resource of the menu to load.
|
||||
* @param album The [Album] to create the menu for.
|
||||
*/
|
||||
protected fun openMusicMenu(anchor: View, @MenuRes menuRes: Int, album: Album) {
|
||||
logD("Launching new album menu: ${album.name}")
|
||||
|
||||
openMenu(anchor, menuRes) {
|
||||
setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
R.id.action_play -> {
|
||||
playbackModel.play(album)
|
||||
true
|
||||
}
|
||||
R.id.action_shuffle -> {
|
||||
playbackModel.shuffle(album)
|
||||
true
|
||||
}
|
||||
R.id.action_play_next -> {
|
||||
playbackModel.playNext(album)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
true
|
||||
}
|
||||
R.id.action_queue_add -> {
|
||||
playbackModel.addToQueue(album)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
true
|
||||
}
|
||||
R.id.action_go_artist -> {
|
||||
detailModel.showArtist(album)
|
||||
true
|
||||
}
|
||||
R.id.action_playlist_add -> {
|
||||
musicModel.addToPlaylist(album)
|
||||
true
|
||||
}
|
||||
R.id.action_share -> {
|
||||
requireContext().share(album)
|
||||
true
|
||||
}
|
||||
else -> {
|
||||
logW("Unexpected menu item selected")
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a menu in the context of a [Artist]. This menu will be managed by the Fragment and
|
||||
* closed when the view is destroyed. If a menu is already opened, this call is ignored.
|
||||
*
|
||||
* @param anchor The [View] to anchor the menu to.
|
||||
* @param menuRes The resource of the menu to load.
|
||||
* @param artist The [Artist] to create the menu for.
|
||||
*/
|
||||
protected fun openMusicMenu(anchor: View, @MenuRes menuRes: Int, artist: Artist) {
|
||||
logD("Launching new artist menu: ${artist.name}")
|
||||
|
||||
openMenu(anchor, menuRes) {
|
||||
val playable = artist.songs.isNotEmpty()
|
||||
if (!playable) {
|
||||
logD("Artist is empty, disabling playback/playlist/share options")
|
||||
}
|
||||
menu.findItem(R.id.action_play).isEnabled = playable
|
||||
menu.findItem(R.id.action_shuffle).isEnabled = playable
|
||||
menu.findItem(R.id.action_play_next).isEnabled = playable
|
||||
menu.findItem(R.id.action_queue_add).isEnabled = playable
|
||||
menu.findItem(R.id.action_playlist_add).isEnabled = playable
|
||||
menu.findItem(R.id.action_share).isEnabled = playable
|
||||
|
||||
setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
R.id.action_play -> {
|
||||
playbackModel.play(artist)
|
||||
true
|
||||
}
|
||||
R.id.action_shuffle -> {
|
||||
playbackModel.shuffle(artist)
|
||||
true
|
||||
}
|
||||
R.id.action_play_next -> {
|
||||
playbackModel.playNext(artist)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
true
|
||||
}
|
||||
R.id.action_queue_add -> {
|
||||
playbackModel.addToQueue(artist)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
true
|
||||
}
|
||||
R.id.action_playlist_add -> {
|
||||
musicModel.addToPlaylist(artist)
|
||||
true
|
||||
}
|
||||
R.id.action_share -> {
|
||||
requireContext().share(artist)
|
||||
true
|
||||
}
|
||||
else -> {
|
||||
logW("Unexpected menu item selected")
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a menu in the context of a [Genre]. This menu will be managed by the Fragment and
|
||||
* closed when the view is destroyed. If a menu is already opened, this call is ignored.
|
||||
*
|
||||
* @param anchor The [View] to anchor the menu to.
|
||||
* @param menuRes The resource of the menu to load.
|
||||
* @param genre The [Genre] to create the menu for.
|
||||
*/
|
||||
protected fun openMusicMenu(anchor: View, @MenuRes menuRes: Int, genre: Genre) {
|
||||
logD("Launching new genre menu: ${genre.name}")
|
||||
|
||||
openMenu(anchor, menuRes) {
|
||||
setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
R.id.action_play -> {
|
||||
playbackModel.play(genre)
|
||||
true
|
||||
}
|
||||
R.id.action_shuffle -> {
|
||||
playbackModel.shuffle(genre)
|
||||
true
|
||||
}
|
||||
R.id.action_play_next -> {
|
||||
playbackModel.playNext(genre)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
true
|
||||
}
|
||||
R.id.action_queue_add -> {
|
||||
playbackModel.addToQueue(genre)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
true
|
||||
}
|
||||
R.id.action_playlist_add -> {
|
||||
musicModel.addToPlaylist(genre)
|
||||
true
|
||||
}
|
||||
R.id.action_share -> {
|
||||
requireContext().share(genre)
|
||||
true
|
||||
}
|
||||
else -> {
|
||||
logW("Unexpected menu item selected")
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a menu in the context of a [Playlist]. This menu will be managed by the Fragment and
|
||||
* closed when the view is destroyed. If a menu is already opened, this call is ignored.
|
||||
*
|
||||
* @param anchor The [View] to anchor the menu to.
|
||||
* @param menuRes The resource of the menu to load.
|
||||
* @param playlist The [Playlist] to create the menu for.
|
||||
*/
|
||||
protected fun openMusicMenu(anchor: View, @MenuRes menuRes: Int, playlist: Playlist) {
|
||||
logD("Launching new playlist menu: ${playlist.name}")
|
||||
|
||||
openMenu(anchor, menuRes) {
|
||||
val playable = playlist.songs.isNotEmpty()
|
||||
menu.findItem(R.id.action_play).isEnabled = playable
|
||||
menu.findItem(R.id.action_shuffle).isEnabled = playable
|
||||
menu.findItem(R.id.action_play_next).isEnabled = playable
|
||||
menu.findItem(R.id.action_queue_add).isEnabled = playable
|
||||
menu.findItem(R.id.action_share).isEnabled = playable
|
||||
|
||||
setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
R.id.action_play -> {
|
||||
playbackModel.play(playlist)
|
||||
true
|
||||
}
|
||||
R.id.action_shuffle -> {
|
||||
playbackModel.shuffle(playlist)
|
||||
true
|
||||
}
|
||||
R.id.action_play_next -> {
|
||||
playbackModel.playNext(playlist)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
true
|
||||
}
|
||||
R.id.action_queue_add -> {
|
||||
playbackModel.addToQueue(playlist)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
true
|
||||
}
|
||||
R.id.action_rename -> {
|
||||
musicModel.renamePlaylist(playlist)
|
||||
true
|
||||
}
|
||||
R.id.action_delete -> {
|
||||
musicModel.deletePlaylist(playlist)
|
||||
true
|
||||
}
|
||||
R.id.action_share -> {
|
||||
requireContext().share(playlist)
|
||||
true
|
||||
}
|
||||
else -> {
|
||||
logW("Unexpected menu item selected")
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a menu. This menu will be managed by the Fragment and closed when the view is destroyed.
|
||||
* If a menu is already opened, this call is ignored.
|
||||
|
|
|
@ -23,7 +23,6 @@ import android.os.Bundle
|
|||
import android.view.LayoutInflater
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.appcompat.view.menu.MenuBuilder
|
||||
import androidx.core.view.children
|
||||
import androidx.navigation.fragment.findNavController
|
||||
|
@ -41,6 +40,8 @@ import org.oxycblt.auxio.util.logD
|
|||
* options.
|
||||
*
|
||||
* @author Alexander Capehart (OxygenCobalt)
|
||||
*
|
||||
* TODO: Handle enabled/disabled states
|
||||
*/
|
||||
abstract class MenuDialogFragment<T : Music> :
|
||||
ViewBindingBottomSheetDialogFragment<DialogMenuBinding>(), ClickableListListener<MenuItem> {
|
||||
|
@ -50,7 +51,7 @@ abstract class MenuDialogFragment<T : Music> :
|
|||
abstract val menuRes: Int
|
||||
abstract val uid: Music.UID
|
||||
abstract fun updateMusic(binding: DialogMenuBinding, music: T)
|
||||
abstract fun onClick(music: T, @IdRes optionId: Int)
|
||||
abstract fun onClick(music: T, item: MenuItem)
|
||||
|
||||
override fun onCreateBinding(inflater: LayoutInflater) = DialogMenuBinding.inflate(inflater)
|
||||
|
||||
|
@ -65,7 +66,7 @@ abstract class MenuDialogFragment<T : Music> :
|
|||
itemAnimator = null
|
||||
}
|
||||
|
||||
// Avoid having to use a dummy view and rely on what AndroidX Toolbar uses.
|
||||
// Avoid having to use a dummy view and just rely on what AndroidX Toolbar uses.
|
||||
@SuppressLint("RestrictedApi") val builder = MenuBuilder(requireContext())
|
||||
MenuInflater(requireContext()).inflate(menuRes, builder)
|
||||
menuAdapter.update(builder.children.toList(), UpdateInstructions.Diff)
|
||||
|
@ -92,6 +93,6 @@ abstract class MenuDialogFragment<T : Music> :
|
|||
|
||||
final override fun onClick(item: MenuItem, viewHolder: RecyclerView.ViewHolder) {
|
||||
findNavController().navigateUp()
|
||||
@Suppress("UNCHECKED_CAST") onClick(menuModel.currentMusic.value as T, item.itemId)
|
||||
@Suppress("UNCHECKED_CAST") onClick(menuModel.currentMusic.value as T, item)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,23 +18,32 @@
|
|||
|
||||
package org.oxycblt.auxio.list.menu
|
||||
|
||||
import android.view.MenuItem
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.databinding.DialogMenuBinding
|
||||
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.Music
|
||||
import org.oxycblt.auxio.music.MusicViewModel
|
||||
import org.oxycblt.auxio.music.Playlist
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.resolveNames
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.util.getPlural
|
||||
import org.oxycblt.auxio.util.share
|
||||
import org.oxycblt.auxio.util.showToast
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SongMenuDialogFragment : MenuDialogFragment<Song>() {
|
||||
override val menuModel: MenuViewModel by activityViewModels()
|
||||
private val detailModel: DetailViewModel by activityViewModels()
|
||||
private val musicModel: MusicViewModel by activityViewModels()
|
||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
||||
private val args: SongMenuDialogFragmentArgs by navArgs()
|
||||
|
||||
override val menuRes: Int
|
||||
|
@ -50,12 +59,32 @@ class SongMenuDialogFragment : MenuDialogFragment<Song>() {
|
|||
binding.menuInfo.text = music.artists.resolveNames(context)
|
||||
}
|
||||
|
||||
override fun onClick(music: Song, optionId: Int) {}
|
||||
override fun onClick(music: Song, item: MenuItem) {
|
||||
when (item.itemId) {
|
||||
R.id.action_play_next -> {
|
||||
playbackModel.playNext(music)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
}
|
||||
R.id.action_queue_add -> {
|
||||
playbackModel.addToQueue(music)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
}
|
||||
R.id.action_go_artist -> detailModel.showArtist(music)
|
||||
R.id.action_go_album -> detailModel.showAlbum(music)
|
||||
R.id.action_share -> requireContext().share(music)
|
||||
R.id.action_playlist_add -> musicModel.addToPlaylist(music)
|
||||
R.id.action_song_detail -> detailModel.showSong(music)
|
||||
else -> error("Unexpected menu item selected $item")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AndroidEntryPoint
|
||||
class AlbumMenuDialogFragment : MenuDialogFragment<Album>() {
|
||||
override val menuModel: MenuViewModel by activityViewModels()
|
||||
private val detailModel: DetailViewModel by activityViewModels()
|
||||
private val musicModel: MusicViewModel by activityViewModels()
|
||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
||||
private val args: AlbumMenuDialogFragmentArgs by navArgs()
|
||||
|
||||
override val menuRes: Int
|
||||
|
@ -71,12 +100,31 @@ class AlbumMenuDialogFragment : MenuDialogFragment<Album>() {
|
|||
binding.menuInfo.text = music.artists.resolveNames(context)
|
||||
}
|
||||
|
||||
override fun onClick(music: Album, optionId: Int) {}
|
||||
override fun onClick(music: Album, item: MenuItem) {
|
||||
when (item.itemId) {
|
||||
R.id.action_play -> playbackModel.play(music)
|
||||
R.id.action_shuffle -> playbackModel.shuffle(music)
|
||||
R.id.action_play_next -> {
|
||||
playbackModel.playNext(music)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
}
|
||||
R.id.action_queue_add -> {
|
||||
playbackModel.addToQueue(music)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
}
|
||||
R.id.action_go_artist -> detailModel.showArtist(music)
|
||||
R.id.action_playlist_add -> musicModel.addToPlaylist(music)
|
||||
R.id.action_share -> requireContext().share(music)
|
||||
else -> error("Unexpected menu item selected $item")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AndroidEntryPoint
|
||||
class ArtistMenuDialogFragment : MenuDialogFragment<Artist>() {
|
||||
override val menuModel: MenuViewModel by activityViewModels()
|
||||
private val musicModel: MusicViewModel by activityViewModels()
|
||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
||||
private val args: ArtistMenuDialogFragmentArgs by navArgs()
|
||||
|
||||
override val menuRes: Int
|
||||
|
@ -100,12 +148,30 @@ class ArtistMenuDialogFragment : MenuDialogFragment<Artist>() {
|
|||
})
|
||||
}
|
||||
|
||||
override fun onClick(music: Artist, optionId: Int) {}
|
||||
override fun onClick(music: Artist, item: MenuItem) {
|
||||
when (item.itemId) {
|
||||
R.id.action_play -> playbackModel.play(music)
|
||||
R.id.action_shuffle -> playbackModel.shuffle(music)
|
||||
R.id.action_play_next -> {
|
||||
playbackModel.playNext(music)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
}
|
||||
R.id.action_queue_add -> {
|
||||
playbackModel.addToQueue(music)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
}
|
||||
R.id.action_playlist_add -> musicModel.addToPlaylist(music)
|
||||
R.id.action_share -> requireContext().share(music)
|
||||
else -> error("Unexpected menu item $item")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AndroidEntryPoint
|
||||
class GenreMenuDialogFragment : MenuDialogFragment<Genre>() {
|
||||
override val menuModel: MenuViewModel by activityViewModels()
|
||||
private val musicModel: MusicViewModel by activityViewModels()
|
||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
||||
private val args: GenreMenuDialogFragmentArgs by navArgs()
|
||||
|
||||
override val menuRes: Int
|
||||
|
@ -125,12 +191,30 @@ class GenreMenuDialogFragment : MenuDialogFragment<Genre>() {
|
|||
context.getPlural(R.plurals.fmt_song_count, music.songs.size))
|
||||
}
|
||||
|
||||
override fun onClick(music: Genre, optionId: Int) {}
|
||||
override fun onClick(music: Genre, item: MenuItem) {
|
||||
when (item.itemId) {
|
||||
R.id.action_play -> playbackModel.play(music)
|
||||
R.id.action_shuffle -> playbackModel.shuffle(music)
|
||||
R.id.action_play_next -> {
|
||||
playbackModel.playNext(music)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
}
|
||||
R.id.action_queue_add -> {
|
||||
playbackModel.addToQueue(music)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
}
|
||||
R.id.action_playlist_add -> musicModel.addToPlaylist(music)
|
||||
R.id.action_share -> requireContext().share(music)
|
||||
else -> error("Unexpected menu item $item")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AndroidEntryPoint
|
||||
class PlaylistMenuDialogFragment : MenuDialogFragment<Playlist>() {
|
||||
override val menuModel: MenuViewModel by activityViewModels()
|
||||
private val musicModel: MusicViewModel by activityViewModels()
|
||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
||||
private val args: PlaylistMenuDialogFragmentArgs by navArgs()
|
||||
|
||||
override val menuRes: Int
|
||||
|
@ -146,5 +230,22 @@ class PlaylistMenuDialogFragment : MenuDialogFragment<Playlist>() {
|
|||
binding.menuInfo.text = context.getPlural(R.plurals.fmt_song_count, music.songs.size)
|
||||
}
|
||||
|
||||
override fun onClick(music: Playlist, optionId: Int) {}
|
||||
override fun onClick(music: Playlist, item: MenuItem) {
|
||||
when (item.itemId) {
|
||||
R.id.action_play -> playbackModel.play(music)
|
||||
R.id.action_shuffle -> playbackModel.shuffle(music)
|
||||
R.id.action_play_next -> {
|
||||
playbackModel.playNext(music)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
}
|
||||
R.id.action_queue_add -> {
|
||||
playbackModel.addToQueue(music)
|
||||
requireContext().showToast(R.string.lng_queue_added)
|
||||
}
|
||||
R.id.action_rename -> musicModel.renamePlaylist(music)
|
||||
R.id.action_delete -> musicModel.deletePlaylist(music)
|
||||
R.id.action_share -> requireContext().share(music)
|
||||
else -> error("Unexpected menu item $item")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue