detail: add queue actions to artist/genre
Add play next/add to queue actions to artists and genres, as the queue system now makes their UX reasonable.
This commit is contained in:
parent
8adf5e978d
commit
5d1eaf72dd
18 changed files with 139 additions and 57 deletions
|
|
@ -18,6 +18,7 @@
|
||||||
- "Rounded album covers" option is no longer dependent on "Show album covers" option
|
- "Rounded album covers" option is no longer dependent on "Show album covers" option
|
||||||
- Added song actions to the playback panel
|
- Added song actions to the playback panel
|
||||||
- Playback controls are now easier to reach when gesture navigation is enabled
|
- Playback controls are now easier to reach when gesture navigation is enabled
|
||||||
|
- Added Play Next/Add to Queue options to artists and genres
|
||||||
|
|
||||||
#### What's Fixed
|
#### What's Fixed
|
||||||
- Playback bar now picks the larger inset in case that gesture inset is missing [#149]
|
- Playback bar now picks the larger inset in case that gesture inset is missing [#149]
|
||||||
|
|
|
||||||
|
|
@ -88,14 +88,17 @@ class MainFragment : ViewBindingFragment<FragmentMainBinding>() {
|
||||||
|
|
||||||
val binding = requireBinding()
|
val binding = requireBinding()
|
||||||
when (action) {
|
when (action) {
|
||||||
MainNavigationAction.EXPAND -> binding.bottomSheetLayout.expand()
|
is MainNavigationAction.Expand -> binding.bottomSheetLayout.expand()
|
||||||
MainNavigationAction.COLLAPSE -> binding.bottomSheetLayout.collapse()
|
is MainNavigationAction.Collapse -> binding.bottomSheetLayout.collapse()
|
||||||
MainNavigationAction.SETTINGS ->
|
is MainNavigationAction.Settings ->
|
||||||
findNavController().navigate(MainFragmentDirections.actionShowSettings())
|
findNavController().navigate(MainFragmentDirections.actionShowSettings())
|
||||||
MainNavigationAction.ABOUT ->
|
is MainNavigationAction.About ->
|
||||||
findNavController().navigate(MainFragmentDirections.actionShowAbout())
|
findNavController().navigate(MainFragmentDirections.actionShowAbout())
|
||||||
MainNavigationAction.QUEUE ->
|
is MainNavigationAction.Queue ->
|
||||||
findNavController().navigate(MainFragmentDirections.actionShowQueue())
|
findNavController().navigate(MainFragmentDirections.actionShowQueue())
|
||||||
|
is MainNavigationAction.SongDetails ->
|
||||||
|
findNavController()
|
||||||
|
.navigate(MainFragmentDirections.actionShowDetails(action.song.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
navModel.finishMainNavigation()
|
navModel.finishMainNavigation()
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,10 @@ class AlbumDetailFragment : DetailFragment(), AlbumDetailAdapter.Listener {
|
||||||
requireContext().showToast(R.string.lbl_queue_added)
|
requireContext().showToast(R.string.lbl_queue_added)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
R.id.action_go_artist -> {
|
||||||
|
navModel.exploreNavigateTo(unlikelyToBeNull(detailModel.currentAlbum.value))
|
||||||
|
true
|
||||||
|
}
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ import org.oxycblt.auxio.util.collectWith
|
||||||
import org.oxycblt.auxio.util.launch
|
import org.oxycblt.auxio.util.launch
|
||||||
import org.oxycblt.auxio.util.logD
|
import org.oxycblt.auxio.util.logD
|
||||||
import org.oxycblt.auxio.util.logW
|
import org.oxycblt.auxio.util.logW
|
||||||
|
import org.oxycblt.auxio.util.showToast
|
||||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -54,7 +55,8 @@ class ArtistDetailFragment : DetailFragment(), DetailAdapter.Listener {
|
||||||
override fun onBindingCreated(binding: FragmentDetailBinding, savedInstanceState: Bundle?) {
|
override fun onBindingCreated(binding: FragmentDetailBinding, savedInstanceState: Bundle?) {
|
||||||
detailModel.setArtistId(args.artistId)
|
detailModel.setArtistId(args.artistId)
|
||||||
|
|
||||||
setupToolbar(unlikelyToBeNull(detailModel.currentArtist.value))
|
setupToolbar(
|
||||||
|
unlikelyToBeNull(detailModel.currentArtist.value), R.menu.menu_genre_artist_detail)
|
||||||
requireBinding().detailRecycler.apply {
|
requireBinding().detailRecycler.apply {
|
||||||
adapter = detailAdapter
|
adapter = detailAdapter
|
||||||
applySpans { pos ->
|
applySpans { pos ->
|
||||||
|
|
@ -72,7 +74,21 @@ class ArtistDetailFragment : DetailFragment(), DetailAdapter.Listener {
|
||||||
launch { playbackModel.song.collectWith(playbackModel.parent, ::updatePlayback) }
|
launch { playbackModel.song.collectWith(playbackModel.parent, ::updatePlayback) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMenuItemClick(item: MenuItem): Boolean = false
|
override fun onMenuItemClick(item: MenuItem): Boolean {
|
||||||
|
return when (item.itemId) {
|
||||||
|
R.id.action_play_next -> {
|
||||||
|
playbackModel.playNext(unlikelyToBeNull(detailModel.currentArtist.value))
|
||||||
|
requireContext().showToast(R.string.lbl_queue_added)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
R.id.action_queue_add -> {
|
||||||
|
playbackModel.addToQueue(unlikelyToBeNull(detailModel.currentArtist.value))
|
||||||
|
requireContext().showToast(R.string.lbl_queue_added)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onItemClick(item: Item) {
|
override fun onItemClick(item: Item) {
|
||||||
when (item) {
|
when (item) {
|
||||||
|
|
|
||||||
|
|
@ -61,14 +61,10 @@ abstract class DetailFragment :
|
||||||
* @param data Parent data to use as the toolbar title
|
* @param data Parent data to use as the toolbar title
|
||||||
* @param menuId Menu resource to use
|
* @param menuId Menu resource to use
|
||||||
*/
|
*/
|
||||||
protected fun setupToolbar(data: MusicParent, @MenuRes menuId: Int = -1) {
|
protected fun setupToolbar(data: MusicParent, @MenuRes menuId: Int) {
|
||||||
requireBinding().detailToolbar.apply {
|
requireBinding().detailToolbar.apply {
|
||||||
title = data.resolveName(context)
|
title = data.resolveName(context)
|
||||||
|
inflateMenu(menuId)
|
||||||
if (menuId != -1) {
|
|
||||||
inflateMenu(menuId)
|
|
||||||
}
|
|
||||||
|
|
||||||
setNavigationOnClickListener { findNavController().navigateUp() }
|
setNavigationOnClickListener { findNavController().navigateUp() }
|
||||||
setOnMenuItemClickListener(this@DetailFragment)
|
setOnMenuItemClickListener(this@DetailFragment)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ import org.oxycblt.auxio.util.applySpans
|
||||||
import org.oxycblt.auxio.util.collectWith
|
import org.oxycblt.auxio.util.collectWith
|
||||||
import org.oxycblt.auxio.util.launch
|
import org.oxycblt.auxio.util.launch
|
||||||
import org.oxycblt.auxio.util.logD
|
import org.oxycblt.auxio.util.logD
|
||||||
|
import org.oxycblt.auxio.util.showToast
|
||||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -54,7 +55,8 @@ class GenreDetailFragment : DetailFragment(), DetailAdapter.Listener {
|
||||||
override fun onBindingCreated(binding: FragmentDetailBinding, savedInstanceState: Bundle?) {
|
override fun onBindingCreated(binding: FragmentDetailBinding, savedInstanceState: Bundle?) {
|
||||||
detailModel.setGenreId(args.genreId)
|
detailModel.setGenreId(args.genreId)
|
||||||
|
|
||||||
setupToolbar(unlikelyToBeNull(detailModel.currentGenre.value))
|
setupToolbar(
|
||||||
|
unlikelyToBeNull(detailModel.currentArtist.value), R.menu.menu_genre_artist_detail)
|
||||||
binding.detailRecycler.apply {
|
binding.detailRecycler.apply {
|
||||||
adapter = detailAdapter
|
adapter = detailAdapter
|
||||||
applySpans { pos ->
|
applySpans { pos ->
|
||||||
|
|
@ -71,7 +73,21 @@ class GenreDetailFragment : DetailFragment(), DetailAdapter.Listener {
|
||||||
launch { playbackModel.song.collectWith(playbackModel.parent, ::updatePlayback) }
|
launch { playbackModel.song.collectWith(playbackModel.parent, ::updatePlayback) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMenuItemClick(item: MenuItem): Boolean = false
|
override fun onMenuItemClick(item: MenuItem): Boolean {
|
||||||
|
return when (item.itemId) {
|
||||||
|
R.id.action_play_next -> {
|
||||||
|
playbackModel.playNext(unlikelyToBeNull(detailModel.currentGenre.value))
|
||||||
|
requireContext().showToast(R.string.lbl_queue_added)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
R.id.action_queue_add -> {
|
||||||
|
playbackModel.addToQueue(unlikelyToBeNull(detailModel.currentGenre.value))
|
||||||
|
requireContext().showToast(R.string.lbl_queue_added)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onItemClick(item: Item) {
|
override fun onItemClick(item: Item) {
|
||||||
when (item) {
|
when (item) {
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,9 @@ import android.text.format.Formatter
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import org.oxycblt.auxio.BuildConfig
|
import androidx.navigation.fragment.navArgs
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.DialogSongDetailBinding
|
import org.oxycblt.auxio.databinding.DialogSongDetailBinding
|
||||||
import org.oxycblt.auxio.music.Song
|
|
||||||
import org.oxycblt.auxio.ui.ViewBindingDialogFragment
|
import org.oxycblt.auxio.ui.ViewBindingDialogFragment
|
||||||
import org.oxycblt.auxio.util.androidActivityViewModels
|
import org.oxycblt.auxio.util.androidActivityViewModels
|
||||||
import org.oxycblt.auxio.util.formatDuration
|
import org.oxycblt.auxio.util.formatDuration
|
||||||
|
|
@ -33,6 +32,7 @@ import org.oxycblt.auxio.util.launch
|
||||||
|
|
||||||
class SongDetailDialog : ViewBindingDialogFragment<DialogSongDetailBinding>() {
|
class SongDetailDialog : ViewBindingDialogFragment<DialogSongDetailBinding>() {
|
||||||
private val detailModel: DetailViewModel by androidActivityViewModels()
|
private val detailModel: DetailViewModel by androidActivityViewModels()
|
||||||
|
private val args: SongDetailDialogArgs by navArgs()
|
||||||
|
|
||||||
override fun onCreateBinding(inflater: LayoutInflater) =
|
override fun onCreateBinding(inflater: LayoutInflater) =
|
||||||
DialogSongDetailBinding.inflate(inflater)
|
DialogSongDetailBinding.inflate(inflater)
|
||||||
|
|
@ -44,7 +44,7 @@ class SongDetailDialog : ViewBindingDialogFragment<DialogSongDetailBinding>() {
|
||||||
|
|
||||||
override fun onBindingCreated(binding: DialogSongDetailBinding, savedInstanceState: Bundle?) {
|
override fun onBindingCreated(binding: DialogSongDetailBinding, savedInstanceState: Bundle?) {
|
||||||
super.onBindingCreated(binding, savedInstanceState)
|
super.onBindingCreated(binding, savedInstanceState)
|
||||||
detailModel.setSongId(requireNotNull(arguments).getLong(ARG_ID))
|
detailModel.setSongId(args.songId)
|
||||||
launch { detailModel.currentSong.collect(::updateSong) }
|
launch { detailModel.currentSong.collect(::updateSong) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,15 +80,4 @@ class SongDetailDialog : ViewBindingDialogFragment<DialogSongDetailBinding>() {
|
||||||
binding.detailContainer.isGone = true
|
binding.detailContainer.isGone = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun from(song: Song): SongDetailDialog {
|
|
||||||
val instance = SongDetailDialog()
|
|
||||||
instance.arguments = Bundle().apply { putLong(ARG_ID, song.id) }
|
|
||||||
return instance
|
|
||||||
}
|
|
||||||
|
|
||||||
const val TAG = BuildConfig.APPLICATION_ID + ".tag.SONG_DETAILS"
|
|
||||||
private const val ARG_ID = BuildConfig.APPLICATION_ID + ".arg.SONG_ID"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -161,11 +161,11 @@ class HomeFragment : ViewBindingFragment<FragmentHomeBinding>(), Toolbar.OnMenuI
|
||||||
}
|
}
|
||||||
R.id.action_settings -> {
|
R.id.action_settings -> {
|
||||||
logD("Navigating to settings")
|
logD("Navigating to settings")
|
||||||
navModel.mainNavigateTo(MainNavigationAction.SETTINGS)
|
navModel.mainNavigateTo(MainNavigationAction.Settings)
|
||||||
}
|
}
|
||||||
R.id.action_about -> {
|
R.id.action_about -> {
|
||||||
logD("Navigating to about")
|
logD("Navigating to about")
|
||||||
navModel.mainNavigateTo(MainNavigationAction.ABOUT)
|
navModel.mainNavigateTo(MainNavigationAction.About)
|
||||||
}
|
}
|
||||||
R.id.submenu_sorting -> {
|
R.id.submenu_sorting -> {
|
||||||
// Junk click event when opening the menu
|
// Junk click event when opening the menu
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ class PlaybackBarFragment : ViewBindingFragment<FragmentPlaybackBarBinding>() {
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
) {
|
) {
|
||||||
binding.root.apply {
|
binding.root.apply {
|
||||||
setOnClickListener { navModel.mainNavigateTo(MainNavigationAction.EXPAND) }
|
setOnClickListener { navModel.mainNavigateTo(MainNavigationAction.Expand) }
|
||||||
|
|
||||||
setOnLongClickListener {
|
setOnLongClickListener {
|
||||||
playbackModel.song.value?.let(navModel::exploreNavigateTo)
|
playbackModel.song.value?.let(navModel::exploreNavigateTo)
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ import androidx.fragment.app.activityViewModels
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.FragmentPlaybackPanelBinding
|
import org.oxycblt.auxio.databinding.FragmentPlaybackPanelBinding
|
||||||
import org.oxycblt.auxio.detail.SongDetailDialog
|
|
||||||
import org.oxycblt.auxio.music.MusicParent
|
import org.oxycblt.auxio.music.MusicParent
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.playback.state.RepeatMode
|
import org.oxycblt.auxio.playback.state.RepeatMode
|
||||||
|
|
@ -80,7 +79,7 @@ class PlaybackPanelFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.playbackToolbar.apply {
|
binding.playbackToolbar.apply {
|
||||||
setNavigationOnClickListener { navModel.mainNavigateTo(MainNavigationAction.COLLAPSE) }
|
setNavigationOnClickListener { navModel.mainNavigateTo(MainNavigationAction.Collapse) }
|
||||||
setOnMenuItemClickListener(this@PlaybackPanelFragment)
|
setOnMenuItemClickListener(this@PlaybackPanelFragment)
|
||||||
queueItem = menu.findItem(R.id.action_queue)
|
queueItem = menu.findItem(R.id.action_queue)
|
||||||
}
|
}
|
||||||
|
|
@ -136,7 +135,7 @@ class PlaybackPanelFragment :
|
||||||
override fun onMenuItemClick(item: MenuItem): Boolean {
|
override fun onMenuItemClick(item: MenuItem): Boolean {
|
||||||
return when (item.itemId) {
|
return when (item.itemId) {
|
||||||
R.id.action_queue -> {
|
R.id.action_queue -> {
|
||||||
navModel.mainNavigateTo(MainNavigationAction.QUEUE)
|
navModel.mainNavigateTo(MainNavigationAction.Queue)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
R.id.action_go_artist -> {
|
R.id.action_go_artist -> {
|
||||||
|
|
@ -149,7 +148,7 @@ class PlaybackPanelFragment :
|
||||||
}
|
}
|
||||||
R.id.action_song_detail -> {
|
R.id.action_song_detail -> {
|
||||||
playbackModel.song.value?.let {
|
playbackModel.song.value?.let {
|
||||||
SongDetailDialog.from(it).show(childFragmentManager, SongDetailDialog.TAG)
|
navModel.mainNavigateTo(MainNavigationAction.SongDetails(it))
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -223,6 +223,16 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback, MusicStore
|
||||||
playbackManager.playNext(settingsManager.detailAlbumSort.songs(album.songs))
|
playbackManager.playNext(settingsManager.detailAlbumSort.songs(album.songs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Add an [Artist] to the top of the queue. */
|
||||||
|
fun playNext(artist: Artist) {
|
||||||
|
playbackManager.playNext(settingsManager.detailArtistSort.songs(artist.songs))
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add a [Genre] to the top of the queue. */
|
||||||
|
fun playNext(genre: Genre) {
|
||||||
|
playbackManager.playNext(settingsManager.detailGenreSort.songs(genre.songs))
|
||||||
|
}
|
||||||
|
|
||||||
/** Add a [Song] to the end of the queue. */
|
/** Add a [Song] to the end of the queue. */
|
||||||
fun addToQueue(song: Song) {
|
fun addToQueue(song: Song) {
|
||||||
playbackManager.addToQueue(song)
|
playbackManager.addToQueue(song)
|
||||||
|
|
@ -233,6 +243,16 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback, MusicStore
|
||||||
playbackManager.addToQueue(settingsManager.detailAlbumSort.songs(album.songs))
|
playbackManager.addToQueue(settingsManager.detailAlbumSort.songs(album.songs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Add an [Artist] to the end of the queue. */
|
||||||
|
fun addToQueue(artist: Artist) {
|
||||||
|
playbackManager.addToQueue(settingsManager.detailArtistSort.songs(artist.songs))
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add a [Genre] to the end of the queue. */
|
||||||
|
fun addToQueue(genre: Genre) {
|
||||||
|
playbackManager.addToQueue(settingsManager.detailGenreSort.songs(genre.songs))
|
||||||
|
}
|
||||||
|
|
||||||
// --- STATUS FUNCTIONS ---
|
// --- STATUS FUNCTIONS ---
|
||||||
|
|
||||||
/** Flip the playing status, e.g from playing to paused */
|
/** Flip the playing status, e.g from playing to paused */
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ import androidx.core.view.children
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.detail.SongDetailDialog
|
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
|
|
@ -55,7 +54,7 @@ fun Fragment.newMenu(anchor: View, data: Item, flag: Int = ActionMenu.FLAG_NONE)
|
||||||
* @throws IllegalStateException When there is no menu for this specific datatype/flag
|
* @throws IllegalStateException When there is no menu for this specific datatype/flag
|
||||||
* @author OxygenCobalt
|
* @author OxygenCobalt
|
||||||
*
|
*
|
||||||
* TODO: Prevent duplicate menus from showing up
|
* TODO: Prevent duplicate menus from showing up (merge into ViewBindingFragment)
|
||||||
*
|
*
|
||||||
* TODO: Add multi-select
|
* TODO: Add multi-select
|
||||||
*/
|
*/
|
||||||
|
|
@ -118,8 +117,8 @@ class ActionMenu(
|
||||||
else -> -1
|
else -> -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Artist -> R.menu.menu_artist_actions
|
is Artist,
|
||||||
is Genre -> R.menu.menu_genre_actions
|
is Genre -> R.menu.menu_genre_artist_actions
|
||||||
else -> -1
|
else -> -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -153,6 +152,14 @@ class ActionMenu(
|
||||||
playbackModel.playNext(data)
|
playbackModel.playNext(data)
|
||||||
context.showToast(R.string.lbl_queue_added)
|
context.showToast(R.string.lbl_queue_added)
|
||||||
}
|
}
|
||||||
|
is Artist -> {
|
||||||
|
playbackModel.playNext(data)
|
||||||
|
context.showToast(R.string.lbl_queue_added)
|
||||||
|
}
|
||||||
|
is Genre -> {
|
||||||
|
playbackModel.playNext(data)
|
||||||
|
context.showToast(R.string.lbl_queue_added)
|
||||||
|
}
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -166,6 +173,14 @@ class ActionMenu(
|
||||||
playbackModel.addToQueue(data)
|
playbackModel.addToQueue(data)
|
||||||
context.showToast(R.string.lbl_queue_added)
|
context.showToast(R.string.lbl_queue_added)
|
||||||
}
|
}
|
||||||
|
is Artist -> {
|
||||||
|
playbackModel.addToQueue(data)
|
||||||
|
context.showToast(R.string.lbl_queue_added)
|
||||||
|
}
|
||||||
|
is Genre -> {
|
||||||
|
playbackModel.addToQueue(data)
|
||||||
|
context.showToast(R.string.lbl_queue_added)
|
||||||
|
}
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -183,8 +198,7 @@ class ActionMenu(
|
||||||
}
|
}
|
||||||
R.id.action_song_detail -> {
|
R.id.action_song_detail -> {
|
||||||
if (data is Song) {
|
if (data is Song) {
|
||||||
SongDetailDialog.from(data)
|
navModel.mainNavigateTo(MainNavigationAction.SongDetails(data))
|
||||||
.show(activity.supportFragmentManager, SongDetailDialog.TAG)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import androidx.lifecycle.ViewModel
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
|
import org.oxycblt.auxio.music.Song
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A ViewModel that handles complicated navigation situations.
|
* A ViewModel that handles complicated navigation situations.
|
||||||
|
|
@ -68,15 +69,17 @@ class NavigationViewModel : ViewModel() {
|
||||||
* normal fragments. This can be passed to [NavigationViewModel.mainNavigateTo] in order to
|
* normal fragments. This can be passed to [NavigationViewModel.mainNavigateTo] in order to
|
||||||
* facilitate navigation without stupid fragment hacks.
|
* facilitate navigation without stupid fragment hacks.
|
||||||
*/
|
*/
|
||||||
enum class MainNavigationAction {
|
sealed class MainNavigationAction {
|
||||||
/** Expand the playback panel. */
|
/** Expand the playback panel. */
|
||||||
EXPAND,
|
object Expand : MainNavigationAction()
|
||||||
/** Collapse the playback panel. */
|
/** Collapse the playback panel. */
|
||||||
COLLAPSE,
|
object Collapse : MainNavigationAction()
|
||||||
/** Go to settings. */
|
/** Go to settings. */
|
||||||
SETTINGS,
|
object Settings : MainNavigationAction()
|
||||||
/** Go to the about page. */
|
/** Go to the about page. */
|
||||||
ABOUT,
|
object About : MainNavigationAction()
|
||||||
/** Go to the queue. */
|
/** Go to the queue. */
|
||||||
QUEUE
|
object Queue : MainNavigationAction()
|
||||||
|
/** Show song details. */
|
||||||
|
data class SongDetails(val song: Song) : MainNavigationAction()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,4 +6,7 @@
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_queue_add"
|
android:id="@+id/action_queue_add"
|
||||||
android:title="@string/lbl_queue_add" />
|
android:title="@string/lbl_queue_add" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_go_artist"
|
||||||
|
android:title="@string/lbl_go_artist" />
|
||||||
</menu>
|
</menu>
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_play"
|
|
||||||
android:title="@string/lbl_play" />
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_shuffle"
|
|
||||||
android:title="@string/lbl_shuffle" />
|
|
||||||
</menu>
|
|
||||||
|
|
@ -6,4 +6,10 @@
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_shuffle"
|
android:id="@+id/action_shuffle"
|
||||||
android:title="@string/lbl_shuffle" />
|
android:title="@string/lbl_shuffle" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_play_next"
|
||||||
|
android:title="@string/lbl_play_next" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_queue_add"
|
||||||
|
android:title="@string/lbl_queue_add" />
|
||||||
</menu>
|
</menu>
|
||||||
9
app/src/main/res/menu/menu_genre_artist_detail.xml
Normal file
9
app/src/main/res/menu/menu_genre_artist_detail.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_play_next"
|
||||||
|
android:title="@string/lbl_play_next" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_queue_add"
|
||||||
|
android:title="@string/lbl_queue_add" />
|
||||||
|
</menu>
|
||||||
|
|
@ -29,6 +29,9 @@
|
||||||
app:exitAnim="@anim/nav_default_exit_anim"
|
app:exitAnim="@anim/nav_default_exit_anim"
|
||||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||||
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_show_details"
|
||||||
|
app:destination="@id/song_detail_dialog" />
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
|
|
@ -46,4 +49,13 @@
|
||||||
android:name="org.oxycblt.auxio.settings.SettingsFragment"
|
android:name="org.oxycblt.auxio.settings.SettingsFragment"
|
||||||
android:label="fragment_settings"
|
android:label="fragment_settings"
|
||||||
tools:layout="@layout/fragment_settings" />
|
tools:layout="@layout/fragment_settings" />
|
||||||
|
<dialog
|
||||||
|
android:id="@+id/song_detail_dialog"
|
||||||
|
android:name="org.oxycblt.auxio.detail.SongDetailDialog"
|
||||||
|
android:label="song_detail_dialog"
|
||||||
|
tools:layout="@layout/dialog_song_detail">
|
||||||
|
<argument
|
||||||
|
android:name="songId"
|
||||||
|
app:argType="long" />
|
||||||
|
</dialog>
|
||||||
</navigation>
|
</navigation>
|
||||||
Loading…
Reference in a new issue