diff --git a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt index 1197a5f78..c1e9db6ff 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt @@ -40,6 +40,8 @@ import org.oxycblt.auxio.list.Header import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.ListFragment import org.oxycblt.auxio.list.Sort +import org.oxycblt.auxio.list.menu.MenuViewModel +import org.oxycblt.auxio.list.menu.PendingMenu import org.oxycblt.auxio.list.selection.SelectionViewModel import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Music @@ -72,6 +74,7 @@ class AlbumDetailFragment : AlbumDetailHeaderAdapter.Listener, DetailListAdapter.Listener { override val detailModel: DetailViewModel by activityViewModels() + private val menuModel: MenuViewModel by activityViewModels() override val selectionModel: SelectionViewModel by activityViewModels() override val musicModel: MusicViewModel by activityViewModels() override val playbackModel: PlaybackViewModel by activityViewModels() @@ -124,6 +127,7 @@ class AlbumDetailFragment : collectImmediately(detailModel.currentAlbum, ::updateAlbum) collectImmediately(detailModel.albumList, ::updateList) collect(detailModel.toShow.flow, ::handleShow) + collect(menuModel.pendingMenu.flow, ::handleMenu) collectImmediately(selectionModel.selected, ::updateSelection) collect(musicModel.playlistDecision.flow, ::handleDecision) collectImmediately( @@ -183,7 +187,7 @@ class AlbumDetailFragment : } override fun onOpenMenu(item: Song, anchor: View) { - openMusicMenu(anchor, R.menu.item_album_song, item) + menuModel.openMenu(R.menu.item_album_song, item) } override fun onPlay() { @@ -300,6 +304,22 @@ class AlbumDetailFragment : } } + private fun handleMenu(pendingMenu: PendingMenu?) { + if (pendingMenu == null) return + val directions = + when (pendingMenu) { + is PendingMenu.ForSong -> + AlbumDetailFragmentDirections.openSongMenu( + pendingMenu.menuRes, pendingMenu.music.uid) + is PendingMenu.ForAlbum, + is PendingMenu.ForArtist, + is PendingMenu.ForGenre, + is PendingMenu.ForPlaylist -> error("Unexpected menu $pendingMenu") + } + findNavController().navigateSafe(directions) + menuModel.pendingMenu.consume() + } + private fun updateSelection(selected: List) { albumListAdapter.setSelected(selected.toSet()) diff --git a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt index b281ec397..61bc0fc4f 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt @@ -40,6 +40,8 @@ import org.oxycblt.auxio.list.Header import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.ListFragment import org.oxycblt.auxio.list.Sort +import org.oxycblt.auxio.list.menu.MenuViewModel +import org.oxycblt.auxio.list.menu.PendingMenu import org.oxycblt.auxio.list.selection.SelectionViewModel import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist @@ -70,6 +72,7 @@ class ArtistDetailFragment : DetailHeaderAdapter.Listener, DetailListAdapter.Listener { override val detailModel: DetailViewModel by activityViewModels() + private val menuModel: MenuViewModel by activityViewModels() override val selectionModel: SelectionViewModel by activityViewModels() override val musicModel: MusicViewModel by activityViewModels() override val playbackModel: PlaybackViewModel by activityViewModels() @@ -125,6 +128,7 @@ class ArtistDetailFragment : collectImmediately(detailModel.currentArtist, ::updateArtist) collectImmediately(detailModel.artistList, ::updateList) collect(detailModel.toShow.flow, ::handleShow) + collect(menuModel.pendingMenu.flow, ::handleMenu) collectImmediately(selectionModel.selected, ::updateSelection) collect(musicModel.playlistDecision.flow, ::handleDecision) collectImmediately( @@ -194,8 +198,8 @@ class ArtistDetailFragment : override fun onOpenMenu(item: Music, anchor: View) { when (item) { - is Song -> openMusicMenu(anchor, R.menu.item_artist_song, item) - is Album -> openMusicMenu(anchor, R.menu.item_artist_album, item) + is Song -> menuModel.openMenu(R.menu.item_artist_song, item) + is Album -> menuModel.openMenu(R.menu.item_artist_album, item) else -> error("Unexpected datatype: ${item::class.simpleName}") } } @@ -310,6 +314,24 @@ class ArtistDetailFragment : } } + private fun handleMenu(pendingMenu: PendingMenu?) { + if (pendingMenu == null) return + val directions = + when (pendingMenu) { + is PendingMenu.ForSong -> + ArtistDetailFragmentDirections.openSongMenu( + pendingMenu.menuRes, pendingMenu.music.uid) + is PendingMenu.ForAlbum -> + ArtistDetailFragmentDirections.openAlbumMenu( + pendingMenu.menuRes, pendingMenu.music.uid) + is PendingMenu.ForArtist, + is PendingMenu.ForGenre, + is PendingMenu.ForPlaylist -> error("Unexpected menu $pendingMenu") + } + findNavController().navigateSafe(directions) + menuModel.pendingMenu.consume() + } + private fun updateSelection(selected: List) { artistListAdapter.setSelected(selected.toSet()) diff --git a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt index a8646fe24..2d393fd01 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt @@ -40,6 +40,8 @@ import org.oxycblt.auxio.list.Header import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.ListFragment import org.oxycblt.auxio.list.Sort +import org.oxycblt.auxio.list.menu.MenuViewModel +import org.oxycblt.auxio.list.menu.PendingMenu import org.oxycblt.auxio.list.selection.SelectionViewModel import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Genre @@ -70,6 +72,7 @@ class GenreDetailFragment : DetailHeaderAdapter.Listener, DetailListAdapter.Listener { override val detailModel: DetailViewModel by activityViewModels() + private val menuModel: MenuViewModel by activityViewModels() override val selectionModel: SelectionViewModel by activityViewModels() override val musicModel: MusicViewModel by activityViewModels() override val playbackModel: PlaybackViewModel by activityViewModels() @@ -123,6 +126,7 @@ class GenreDetailFragment : collectImmediately(detailModel.currentGenre, ::updatePlaylist) collectImmediately(detailModel.genreList, ::updateList) collect(detailModel.toShow.flow, ::handleShow) + collect(menuModel.pendingMenu.flow, ::handleMenu) collectImmediately(selectionModel.selected, ::updateSelection) collect(musicModel.playlistDecision.flow, ::handleDecision) collectImmediately( @@ -192,8 +196,8 @@ class GenreDetailFragment : override fun onOpenMenu(item: Music, anchor: View) { when (item) { - is Artist -> openMusicMenu(anchor, R.menu.item_parent, item) - is Song -> openMusicMenu(anchor, R.menu.item_song, item) + is Artist -> menuModel.openMenu(R.menu.item_parent, item) + is Song -> menuModel.openMenu(R.menu.item_song, item) else -> error("Unexpected datatype: ${item::class.simpleName}") } } @@ -298,6 +302,24 @@ class GenreDetailFragment : } } + private fun handleMenu(pendingMenu: PendingMenu?) { + if (pendingMenu == null) return + val directions = + when (pendingMenu) { + is PendingMenu.ForSong -> + GenreDetailFragmentDirections.openSongMenu( + pendingMenu.menuRes, pendingMenu.music.uid) + is PendingMenu.ForArtist -> + GenreDetailFragmentDirections.openArtistMenu( + pendingMenu.menuRes, pendingMenu.music.uid) + is PendingMenu.ForAlbum, + is PendingMenu.ForGenre, + is PendingMenu.ForPlaylist -> error("Unexpected menu $pendingMenu") + } + findNavController().navigateSafe(directions) + menuModel.pendingMenu.consume() + } + private fun updateSelection(selected: List) { genreListAdapter.setSelected(selected.toSet()) diff --git a/app/src/main/java/org/oxycblt/auxio/detail/PlaylistDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/PlaylistDetailFragment.kt index b444abfdb..f97a745f9 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/PlaylistDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/PlaylistDetailFragment.kt @@ -43,6 +43,8 @@ import org.oxycblt.auxio.list.Divider import org.oxycblt.auxio.list.Header import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.ListFragment +import org.oxycblt.auxio.list.menu.MenuViewModel +import org.oxycblt.auxio.list.menu.PendingMenu import org.oxycblt.auxio.list.selection.SelectionViewModel import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.MusicParent @@ -73,6 +75,7 @@ class PlaylistDetailFragment : PlaylistDetailListAdapter.Listener, NavController.OnDestinationChangedListener { override val detailModel: DetailViewModel by activityViewModels() + private val menuModel: MenuViewModel by activityViewModels() override val selectionModel: SelectionViewModel by activityViewModels() override val musicModel: MusicViewModel by activityViewModels() override val playbackModel: PlaybackViewModel by activityViewModels() @@ -138,6 +141,7 @@ class PlaylistDetailFragment : collectImmediately(detailModel.playlistList, ::updateList) collectImmediately(detailModel.editedPlaylist, ::updateEditedList) collect(detailModel.toShow.flow, ::handleShow) + collect(menuModel.pendingMenu.flow, ::handleMenu) collectImmediately(selectionModel.selected, ::updateSelection) collect(musicModel.playlistDecision.flow, ::handleDecision) collectImmediately( @@ -235,7 +239,7 @@ class PlaylistDetailFragment : } override fun onOpenMenu(item: Song, anchor: View) { - openMusicMenu(anchor, R.menu.item_playlist_song, item) + menuModel.openMenu(R.menu.item_playlist_song, item) } override fun onPlay() { @@ -345,6 +349,22 @@ class PlaylistDetailFragment : } } + private fun handleMenu(pendingMenu: PendingMenu?) { + if (pendingMenu == null) return + val directions = + when (pendingMenu) { + is PendingMenu.ForSong -> + PlaylistDetailFragmentDirections.openSongMenu( + pendingMenu.menuRes, pendingMenu.music.uid) + is PendingMenu.ForArtist, + is PendingMenu.ForAlbum, + is PendingMenu.ForGenre, + is PendingMenu.ForPlaylist -> error("Unexpected menu $pendingMenu") + } + findNavController().navigateSafe(directions) + menuModel.pendingMenu.consume() + } + private fun updateSelection(selected: List) { playlistListAdapter.setSelected(selected.toSet()) diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt index 4a878826f..d0df07da6 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt @@ -56,6 +56,8 @@ import org.oxycblt.auxio.home.list.SongListFragment import org.oxycblt.auxio.home.tabs.AdaptiveTabStrategy import org.oxycblt.auxio.home.tabs.Tab import org.oxycblt.auxio.list.Sort +import org.oxycblt.auxio.list.menu.MenuViewModel +import org.oxycblt.auxio.list.menu.PendingMenu import org.oxycblt.auxio.list.selection.SelectionFragment import org.oxycblt.auxio.list.selection.SelectionViewModel import org.oxycblt.auxio.music.IndexingProgress @@ -87,6 +89,7 @@ import org.oxycblt.auxio.util.unlikelyToBeNull @AndroidEntryPoint class HomeFragment : SelectionFragment(), AppBarLayout.OnOffsetChangedListener { + private val menuModel: MenuViewModel by activityViewModels() override val selectionModel: SelectionViewModel by activityViewModels() override val musicModel: MusicViewModel by activityViewModels() override val playbackModel: PlaybackViewModel by activityViewModels() @@ -175,6 +178,7 @@ class HomeFragment : collect(homeModel.recreateTabs.flow, ::handleRecreate) collectImmediately(homeModel.currentTabMode, ::updateCurrentTab) collectImmediately(homeModel.songsList, homeModel.isFastScrolling, ::updateFab) + collect(menuModel.pendingMenu.flow, ::handleMenu) collectImmediately(selectionModel.selected, ::updateSelection) collectImmediately(musicModel.indexingState, ::updateIndexerState) collect(musicModel.playlistDecision.flow, ::handleDecision) @@ -584,6 +588,27 @@ class HomeFragment : } } + private fun handleMenu(pendingMenu: PendingMenu?) { + if (pendingMenu == null) return + val directions = + when (pendingMenu) { + is PendingMenu.ForSong -> + HomeFragmentDirections.openSongMenu(pendingMenu.menuRes, pendingMenu.music.uid) + is PendingMenu.ForAlbum -> + HomeFragmentDirections.openAlbumMenu(pendingMenu.menuRes, pendingMenu.music.uid) + is PendingMenu.ForArtist -> + HomeFragmentDirections.openArtistMenu( + pendingMenu.menuRes, pendingMenu.music.uid) + is PendingMenu.ForGenre -> + HomeFragmentDirections.openGenreMenu(pendingMenu.menuRes, pendingMenu.music.uid) + is PendingMenu.ForPlaylist -> + HomeFragmentDirections.openPlaylistMenu( + pendingMenu.menuRes, pendingMenu.music.uid) + } + findNavController().navigateSafe(directions) + menuModel.pendingMenu.consume() + } + private fun updateSelection(selected: List) { val binding = requireBinding() if (selected.isNotEmpty()) { diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt index f6ed98f88..9bf2bc05c 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt @@ -35,6 +35,7 @@ import org.oxycblt.auxio.list.ListFragment import org.oxycblt.auxio.list.SelectableListListener import org.oxycblt.auxio.list.Sort import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter +import org.oxycblt.auxio.list.menu.MenuViewModel import org.oxycblt.auxio.list.recycler.AlbumViewHolder import org.oxycblt.auxio.list.selection.SelectionViewModel import org.oxycblt.auxio.music.Album @@ -60,9 +61,10 @@ class AlbumListFragment : FastScrollRecyclerView.PopupProvider { private val homeModel: HomeViewModel by activityViewModels() override val detailModel: DetailViewModel by activityViewModels() - override val playbackModel: PlaybackViewModel by activityViewModels() - override val musicModel: MusicViewModel by activityViewModels() + private val menuModel: MenuViewModel by activityViewModels() override val selectionModel: SelectionViewModel by activityViewModels() + override val musicModel: MusicViewModel by activityViewModels() + override val playbackModel: PlaybackViewModel by activityViewModels() private val albumAdapter = AlbumAdapter(this) // Save memory by re-using the same formatter and string builder when creating popup text private val formatterSb = StringBuilder(64) diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt index 86fdc3483..f994e4abe 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt @@ -33,6 +33,7 @@ import org.oxycblt.auxio.list.ListFragment import org.oxycblt.auxio.list.SelectableListListener import org.oxycblt.auxio.list.Sort import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter +import org.oxycblt.auxio.list.menu.MenuViewModel import org.oxycblt.auxio.list.recycler.ArtistViewHolder import org.oxycblt.auxio.list.selection.SelectionViewModel import org.oxycblt.auxio.music.Artist @@ -58,9 +59,10 @@ class ArtistListFragment : FastScrollRecyclerView.Listener { private val homeModel: HomeViewModel by activityViewModels() override val detailModel: DetailViewModel by activityViewModels() - override val playbackModel: PlaybackViewModel by activityViewModels() - override val musicModel: MusicViewModel by activityViewModels() + private val menuModel: MenuViewModel by activityViewModels() override val selectionModel: SelectionViewModel by activityViewModels() + override val musicModel: MusicViewModel by activityViewModels() + override val playbackModel: PlaybackViewModel by activityViewModels() private val artistAdapter = ArtistAdapter(this) override fun onCreateBinding(inflater: LayoutInflater) = @@ -118,7 +120,7 @@ class ArtistListFragment : } override fun onOpenMenu(item: Artist, anchor: View) { - openMusicMenu(anchor, R.menu.item_parent, item) + menuModel.openMenu(R.menu.item_parent, item) } private fun updateArtists(artists: List) { diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt index 46c26f689..f4d3bd31b 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt @@ -33,6 +33,7 @@ import org.oxycblt.auxio.list.ListFragment import org.oxycblt.auxio.list.SelectableListListener import org.oxycblt.auxio.list.Sort import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter +import org.oxycblt.auxio.list.menu.MenuViewModel import org.oxycblt.auxio.list.recycler.GenreViewHolder import org.oxycblt.auxio.list.selection.SelectionViewModel import org.oxycblt.auxio.music.Genre @@ -57,9 +58,10 @@ class GenreListFragment : FastScrollRecyclerView.Listener { private val homeModel: HomeViewModel by activityViewModels() override val detailModel: DetailViewModel by activityViewModels() - override val playbackModel: PlaybackViewModel by activityViewModels() - override val musicModel: MusicViewModel by activityViewModels() + private val menuModel: MenuViewModel by activityViewModels() override val selectionModel: SelectionViewModel by activityViewModels() + override val musicModel: MusicViewModel by activityViewModels() + override val playbackModel: PlaybackViewModel by activityViewModels() private val genreAdapter = GenreAdapter(this) override fun onCreateBinding(inflater: LayoutInflater) = @@ -117,7 +119,7 @@ class GenreListFragment : } override fun onOpenMenu(item: Genre, anchor: View) { - openMusicMenu(anchor, R.menu.item_parent, item) + menuModel.openMenu(R.menu.item_parent, item) } private fun updateGenres(genres: List) { diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/PlaylistListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/PlaylistListFragment.kt index cef433bde..edf1c9780 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/PlaylistListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/PlaylistListFragment.kt @@ -32,6 +32,7 @@ import org.oxycblt.auxio.list.ListFragment import org.oxycblt.auxio.list.SelectableListListener import org.oxycblt.auxio.list.Sort import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter +import org.oxycblt.auxio.list.menu.MenuViewModel import org.oxycblt.auxio.list.recycler.PlaylistViewHolder import org.oxycblt.auxio.list.selection.SelectionViewModel import org.oxycblt.auxio.music.Music @@ -55,9 +56,10 @@ class PlaylistListFragment : FastScrollRecyclerView.Listener { private val homeModel: HomeViewModel by activityViewModels() override val detailModel: DetailViewModel by activityViewModels() - override val playbackModel: PlaybackViewModel by activityViewModels() - override val musicModel: MusicViewModel by activityViewModels() + private val menuModel: MenuViewModel by activityViewModels() override val selectionModel: SelectionViewModel by activityViewModels() + override val musicModel: MusicViewModel by activityViewModels() + override val playbackModel: PlaybackViewModel by activityViewModels() private val playlistAdapter = PlaylistAdapter(this) override fun onCreateBinding(inflater: LayoutInflater) = @@ -115,7 +117,7 @@ class PlaylistListFragment : } override fun onOpenMenu(item: Playlist, anchor: View) { - openMusicMenu(anchor, R.menu.item_playlist, item) + menuModel.openMenu(R.menu.item_playlist, item) } private fun updatePlaylists(playlists: List) { diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt index b22366658..52f64f8bb 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt @@ -35,6 +35,7 @@ import org.oxycblt.auxio.list.ListFragment import org.oxycblt.auxio.list.SelectableListListener import org.oxycblt.auxio.list.Sort import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter +import org.oxycblt.auxio.list.menu.MenuViewModel import org.oxycblt.auxio.list.recycler.SongViewHolder import org.oxycblt.auxio.list.selection.SelectionViewModel import org.oxycblt.auxio.music.Music @@ -59,9 +60,10 @@ class SongListFragment : FastScrollRecyclerView.Listener { private val homeModel: HomeViewModel by activityViewModels() override val detailModel: DetailViewModel by activityViewModels() - override val playbackModel: PlaybackViewModel by activityViewModels() - override val musicModel: MusicViewModel by activityViewModels() + private val menuModel: MenuViewModel by activityViewModels() override val selectionModel: SelectionViewModel by activityViewModels() + override val musicModel: MusicViewModel by activityViewModels() + override val playbackModel: PlaybackViewModel by activityViewModels() private val songAdapter = SongAdapter(this) // Save memory by re-using the same formatter and string builder when creating popup text private val formatterSb = StringBuilder(64) @@ -143,7 +145,7 @@ class SongListFragment : } override fun onOpenMenu(item: Song, anchor: View) { - openMusicMenu(anchor, R.menu.item_song, item) + menuModel.openMenu(R.menu.item_song, item) } private fun updateSongs(songs: List) { diff --git a/app/src/main/java/org/oxycblt/auxio/list/menu/MenuDialogFragment.kt b/app/src/main/java/org/oxycblt/auxio/list/menu/MenuDialogFragment.kt index 1f0317ae8..e9d20edff 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/menu/MenuDialogFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/menu/MenuDialogFragment.kt @@ -71,7 +71,7 @@ abstract class MenuDialogFragment : menuAdapter.update(builder.children.toList(), UpdateInstructions.Diff) // --- VIEWMODEL SETUP --- - menuModel.setMusic(uid) + menuModel.setCurrentMenu(uid) collectImmediately(menuModel.currentMusic, this::updateMusic) } diff --git a/app/src/main/java/org/oxycblt/auxio/list/menu/MenuDialogFragmentImpl.kt b/app/src/main/java/org/oxycblt/auxio/list/menu/MenuDialogFragmentImpl.kt index 9c1f8f7cc..e68af70ca 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/menu/MenuDialogFragmentImpl.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/menu/MenuDialogFragmentImpl.kt @@ -18,7 +18,7 @@ package org.oxycblt.auxio.list.menu -import androidx.fragment.app.viewModels +import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.navArgs import dagger.hilt.android.AndroidEntryPoint import org.oxycblt.auxio.R @@ -34,7 +34,7 @@ import org.oxycblt.auxio.util.getPlural @AndroidEntryPoint class SongMenuDialogFragment : MenuDialogFragment() { - override val menuModel: MenuViewModel by viewModels() + override val menuModel: MenuViewModel by activityViewModels() private val args: SongMenuDialogFragmentArgs by navArgs() override val menuRes: Int @@ -55,7 +55,7 @@ class SongMenuDialogFragment : MenuDialogFragment() { @AndroidEntryPoint class AlbumMenuDialogFragment : MenuDialogFragment() { - override val menuModel: MenuViewModel by viewModels() + override val menuModel: MenuViewModel by activityViewModels() private val args: AlbumMenuDialogFragmentArgs by navArgs() override val menuRes: Int @@ -76,7 +76,7 @@ class AlbumMenuDialogFragment : MenuDialogFragment() { @AndroidEntryPoint class ArtistMenuDialogFragment : MenuDialogFragment() { - override val menuModel: MenuViewModel by viewModels() + override val menuModel: MenuViewModel by activityViewModels() private val args: ArtistMenuDialogFragmentArgs by navArgs() override val menuRes: Int @@ -105,7 +105,7 @@ class ArtistMenuDialogFragment : MenuDialogFragment() { @AndroidEntryPoint class GenreMenuDialogFragment : MenuDialogFragment() { - override val menuModel: MenuViewModel by viewModels() + override val menuModel: MenuViewModel by activityViewModels() private val args: GenreMenuDialogFragmentArgs by navArgs() override val menuRes: Int @@ -130,7 +130,7 @@ class GenreMenuDialogFragment : MenuDialogFragment() { @AndroidEntryPoint class PlaylistMenuDialogFragment : MenuDialogFragment() { - override val menuModel: MenuViewModel by viewModels() + override val menuModel: MenuViewModel by activityViewModels() private val args: PlaylistMenuDialogFragmentArgs by navArgs() override val menuRes: Int diff --git a/app/src/main/java/org/oxycblt/auxio/list/menu/MenuViewModel.kt b/app/src/main/java/org/oxycblt/auxio/list/menu/MenuViewModel.kt index 91fccff25..af27a2e99 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/menu/MenuViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/menu/MenuViewModel.kt @@ -18,18 +18,29 @@ package org.oxycblt.auxio.list.menu +import androidx.annotation.MenuRes import androidx.lifecycle.ViewModel import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +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.MusicRepository +import org.oxycblt.auxio.music.Playlist +import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.util.Event +import org.oxycblt.auxio.util.MutableEvent import org.oxycblt.auxio.util.logW @HiltViewModel class MenuViewModel @Inject constructor(private val musicRepository: MusicRepository) : ViewModel(), MusicRepository.UpdateListener { + private val _pendingMenu = MutableEvent() + val pendingMenu: Event = _pendingMenu + private val _currentMusic = MutableStateFlow(null) val currentMusic: StateFlow = _currentMusic @@ -45,10 +56,46 @@ class MenuViewModel @Inject constructor(private val musicRepository: MusicReposi musicRepository.removeUpdateListener(this) } - fun setMusic(uid: Music.UID) { + fun openMenu(@MenuRes menuRes: Int, song: Song) = + openMenuImpl(PendingMenu.ForSong(menuRes, song)) + + fun openMenu(@MenuRes menuRes: Int, album: Album) = + openMenuImpl(PendingMenu.ForAlbum(menuRes, album)) + + fun openMenu(@MenuRes menuRes: Int, artist: Artist) = + openMenuImpl(PendingMenu.ForArtist(menuRes, artist)) + + fun openMenu(@MenuRes menuRes: Int, genre: Genre) = + openMenuImpl(PendingMenu.ForGenre(menuRes, genre)) + + fun openMenu(@MenuRes menuRes: Int, playlist: Playlist) = + openMenuImpl(PendingMenu.ForPlaylist(menuRes, playlist)) + + private fun openMenuImpl(pendingMenu: PendingMenu) { + val existing = _pendingMenu.flow.value + if (existing != null) { + logW("Already opening $existing, ignoring $pendingMenu") + return + } + _pendingMenu.put(pendingMenu) + } + + fun setCurrentMenu(uid: Music.UID) { _currentMusic.value = musicRepository.find(uid) if (_currentMusic.value == null) { logW("Given Music UID to show was invalid") } } } + +sealed interface PendingMenu { + val menuRes: Int + val music: Music + + class ForSong(@MenuRes override val menuRes: Int, override val music: Song) : PendingMenu + class ForAlbum(@MenuRes override val menuRes: Int, override val music: Album) : PendingMenu + class ForArtist(@MenuRes override val menuRes: Int, override val music: Artist) : PendingMenu + class ForGenre(@MenuRes override val menuRes: Int, override val music: Genre) : PendingMenu + class ForPlaylist(@MenuRes override val menuRes: Int, override val music: Playlist) : + PendingMenu +} diff --git a/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt b/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt index ff41e9910..7d0e8e4e8 100644 --- a/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt @@ -36,11 +36,12 @@ import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentSearchBinding import org.oxycblt.auxio.detail.DetailViewModel import org.oxycblt.auxio.detail.Show -import org.oxycblt.auxio.home.HomeFragmentDirections import org.oxycblt.auxio.list.Divider import org.oxycblt.auxio.list.Header import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.ListFragment +import org.oxycblt.auxio.list.menu.MenuViewModel +import org.oxycblt.auxio.list.menu.PendingMenu import org.oxycblt.auxio.list.selection.SelectionViewModel import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist @@ -71,9 +72,10 @@ import org.oxycblt.auxio.util.setFullWidthLookup @AndroidEntryPoint class SearchFragment : ListFragment() { override val detailModel: DetailViewModel by activityViewModels() + private val menuModel: MenuViewModel by activityViewModels() + override val selectionModel: SelectionViewModel by activityViewModels() override val playbackModel: PlaybackViewModel by activityViewModels() override val musicModel: MusicViewModel by activityViewModels() - override val selectionModel: SelectionViewModel by activityViewModels() private val searchModel: SearchViewModel by viewModels() private val searchAdapter = SearchAdapter(this) private var imm: InputMethodManager? = null @@ -138,6 +140,7 @@ class SearchFragment : ListFragment() { // --- VIEWMODEL SETUP --- collectImmediately(searchModel.searchResults, ::updateSearchResults) + collect(menuModel.pendingMenu.flow, ::handleMenu) collectImmediately(selectionModel.selected, ::updateSelection) collect(musicModel.playlistDecision.flow, ::handleDecision) collectImmediately( @@ -181,11 +184,11 @@ class SearchFragment : ListFragment() { override fun onOpenMenu(item: Music, anchor: View) { when (item) { - is Song -> openMusicMenu(anchor, R.menu.item_song, item) - is Album -> openMusicMenu(anchor, R.menu.item_album, item) - is Artist -> openMusicMenu(anchor, R.menu.item_parent, item) - is Genre -> openMusicMenu(anchor, R.menu.item_parent, item) - is Playlist -> openMusicMenu(anchor, R.menu.item_playlist, item) + is Song -> menuModel.openMenu(R.menu.item_song, item) + is Album -> menuModel.openMenu(R.menu.item_album, item) + is Artist -> menuModel.openMenu(R.menu.item_parent, item) + is Genre -> menuModel.openMenu(R.menu.item_parent, item) + is Playlist -> menuModel.openMenu(R.menu.item_playlist, item) } } @@ -247,7 +250,7 @@ class SearchFragment : ListFragment() { is Show.PlaylistDetails -> { logD("Navigating to ${show.playlist}") findNavController() - .navigateSafe(SearchFragmentDirections.showGenre(show.playlist.uid)) + .navigateSafe(SearchFragmentDirections.showPlaylist(show.playlist.uid)) } null -> {} } @@ -258,32 +261,26 @@ class SearchFragment : ListFragment() { private fun handleDecision(decision: PlaylistDecision?) { if (decision == null) return - when (decision) { - is PlaylistDecision.New -> { - logD("Creating new playlist") - findNavController() - .navigateSafe( - HomeFragmentDirections.newPlaylist( - decision.songs.map { it.uid }.toTypedArray())) + 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") + } } - is PlaylistDecision.Rename -> { - logD("Renaming ${decision.playlist}") - findNavController() - .navigateSafe(HomeFragmentDirections.renamePlaylist(decision.playlist.uid)) - } - is PlaylistDecision.Delete -> { - logD("Deleting ${decision.playlist}") - findNavController() - .navigateSafe(SearchFragmentDirections.deletePlaylist(decision.playlist.uid)) - } - is PlaylistDecision.Add -> { - logD("Adding ${decision.songs.size} to a playlist") - findNavController() - .navigateSafe( - HomeFragmentDirections.addToPlaylist( - decision.songs.map { it.uid }.toTypedArray())) - } - } + findNavController().navigateSafe(directions) musicModel.playlistDecision.consume() } @@ -291,6 +288,30 @@ class SearchFragment : ListFragment() { searchAdapter.setPlaying(parent ?: song, isPlaying) } + private fun handleMenu(pendingMenu: PendingMenu?) { + if (pendingMenu == null) return + val directions = + when (pendingMenu) { + is PendingMenu.ForSong -> + SearchFragmentDirections.openSongMenu( + pendingMenu.menuRes, pendingMenu.music.uid) + is PendingMenu.ForAlbum -> + SearchFragmentDirections.openAlbumMenu( + pendingMenu.menuRes, pendingMenu.music.uid) + is PendingMenu.ForArtist -> + SearchFragmentDirections.openArtistMenu( + pendingMenu.menuRes, pendingMenu.music.uid) + is PendingMenu.ForGenre -> + SearchFragmentDirections.openGenreMenu( + pendingMenu.menuRes, pendingMenu.music.uid) + is PendingMenu.ForPlaylist -> + SearchFragmentDirections.openPlaylistMenu( + pendingMenu.menuRes, pendingMenu.music.uid) + } + findNavController().navigateSafe(directions) + menuModel.pendingMenu.consume() + } + private fun updateSelection(selected: List) { searchAdapter.setSelected(selected.toSet()) val binding = requireBinding() diff --git a/app/src/main/res/layout/dialog_menu.xml b/app/src/main/res/layout/dialog_menu.xml index f7dbc37af..c685bfc9a 100644 --- a/app/src/main/res/layout/dialog_menu.xml +++ b/app/src/main/res/layout/dialog_menu.xml @@ -2,26 +2,28 @@ - + + \ No newline at end of file diff --git a/app/src/main/res/navigation/main.xml b/app/src/main/res/navigation/main.xml index ea498b24f..cb0ddb39b 100644 --- a/app/src/main/res/navigation/main.xml +++ b/app/src/main/res/navigation/main.xml @@ -33,6 +33,21 @@ + + + + + @@ -86,6 +101,21 @@ + + + + + @@ -123,12 +153,15 @@ - + + @@ -154,6 +187,12 @@ + + @@ -182,6 +221,12 @@ + + @@ -210,6 +255,9 @@ +