all: use menu everywhere
Use the new menu system in all applicable places. More consideration is needed right now on whether the toolbars should also have menu items, so they remain unchanged right now.
This commit is contained in:
parent
0d896c04e3
commit
d6a20fedb3
16 changed files with 325 additions and 78 deletions
|
@ -40,6 +40,8 @@ import org.oxycblt.auxio.list.Header
|
||||||
import org.oxycblt.auxio.list.Item
|
import org.oxycblt.auxio.list.Item
|
||||||
import org.oxycblt.auxio.list.ListFragment
|
import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.Sort
|
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.list.selection.SelectionViewModel
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
|
@ -72,6 +74,7 @@ class AlbumDetailFragment :
|
||||||
AlbumDetailHeaderAdapter.Listener,
|
AlbumDetailHeaderAdapter.Listener,
|
||||||
DetailListAdapter.Listener<Song> {
|
DetailListAdapter.Listener<Song> {
|
||||||
override val detailModel: DetailViewModel by activityViewModels()
|
override val detailModel: DetailViewModel by activityViewModels()
|
||||||
|
private val menuModel: MenuViewModel by activityViewModels()
|
||||||
override val selectionModel: SelectionViewModel by activityViewModels()
|
override val selectionModel: SelectionViewModel by activityViewModels()
|
||||||
override val musicModel: MusicViewModel by activityViewModels()
|
override val musicModel: MusicViewModel by activityViewModels()
|
||||||
override val playbackModel: PlaybackViewModel by activityViewModels()
|
override val playbackModel: PlaybackViewModel by activityViewModels()
|
||||||
|
@ -124,6 +127,7 @@ class AlbumDetailFragment :
|
||||||
collectImmediately(detailModel.currentAlbum, ::updateAlbum)
|
collectImmediately(detailModel.currentAlbum, ::updateAlbum)
|
||||||
collectImmediately(detailModel.albumList, ::updateList)
|
collectImmediately(detailModel.albumList, ::updateList)
|
||||||
collect(detailModel.toShow.flow, ::handleShow)
|
collect(detailModel.toShow.flow, ::handleShow)
|
||||||
|
collect(menuModel.pendingMenu.flow, ::handleMenu)
|
||||||
collectImmediately(selectionModel.selected, ::updateSelection)
|
collectImmediately(selectionModel.selected, ::updateSelection)
|
||||||
collect(musicModel.playlistDecision.flow, ::handleDecision)
|
collect(musicModel.playlistDecision.flow, ::handleDecision)
|
||||||
collectImmediately(
|
collectImmediately(
|
||||||
|
@ -183,7 +187,7 @@ class AlbumDetailFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOpenMenu(item: Song, anchor: View) {
|
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() {
|
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<Music>) {
|
private fun updateSelection(selected: List<Music>) {
|
||||||
albumListAdapter.setSelected(selected.toSet())
|
albumListAdapter.setSelected(selected.toSet())
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,8 @@ import org.oxycblt.auxio.list.Header
|
||||||
import org.oxycblt.auxio.list.Item
|
import org.oxycblt.auxio.list.Item
|
||||||
import org.oxycblt.auxio.list.ListFragment
|
import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.Sort
|
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.list.selection.SelectionViewModel
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
|
@ -70,6 +72,7 @@ class ArtistDetailFragment :
|
||||||
DetailHeaderAdapter.Listener,
|
DetailHeaderAdapter.Listener,
|
||||||
DetailListAdapter.Listener<Music> {
|
DetailListAdapter.Listener<Music> {
|
||||||
override val detailModel: DetailViewModel by activityViewModels()
|
override val detailModel: DetailViewModel by activityViewModels()
|
||||||
|
private val menuModel: MenuViewModel by activityViewModels()
|
||||||
override val selectionModel: SelectionViewModel by activityViewModels()
|
override val selectionModel: SelectionViewModel by activityViewModels()
|
||||||
override val musicModel: MusicViewModel by activityViewModels()
|
override val musicModel: MusicViewModel by activityViewModels()
|
||||||
override val playbackModel: PlaybackViewModel by activityViewModels()
|
override val playbackModel: PlaybackViewModel by activityViewModels()
|
||||||
|
@ -125,6 +128,7 @@ class ArtistDetailFragment :
|
||||||
collectImmediately(detailModel.currentArtist, ::updateArtist)
|
collectImmediately(detailModel.currentArtist, ::updateArtist)
|
||||||
collectImmediately(detailModel.artistList, ::updateList)
|
collectImmediately(detailModel.artistList, ::updateList)
|
||||||
collect(detailModel.toShow.flow, ::handleShow)
|
collect(detailModel.toShow.flow, ::handleShow)
|
||||||
|
collect(menuModel.pendingMenu.flow, ::handleMenu)
|
||||||
collectImmediately(selectionModel.selected, ::updateSelection)
|
collectImmediately(selectionModel.selected, ::updateSelection)
|
||||||
collect(musicModel.playlistDecision.flow, ::handleDecision)
|
collect(musicModel.playlistDecision.flow, ::handleDecision)
|
||||||
collectImmediately(
|
collectImmediately(
|
||||||
|
@ -194,8 +198,8 @@ class ArtistDetailFragment :
|
||||||
|
|
||||||
override fun onOpenMenu(item: Music, anchor: View) {
|
override fun onOpenMenu(item: Music, anchor: View) {
|
||||||
when (item) {
|
when (item) {
|
||||||
is Song -> openMusicMenu(anchor, R.menu.item_artist_song, item)
|
is Song -> menuModel.openMenu(R.menu.item_artist_song, item)
|
||||||
is Album -> openMusicMenu(anchor, R.menu.item_artist_album, item)
|
is Album -> menuModel.openMenu(R.menu.item_artist_album, item)
|
||||||
else -> error("Unexpected datatype: ${item::class.simpleName}")
|
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<Music>) {
|
private fun updateSelection(selected: List<Music>) {
|
||||||
artistListAdapter.setSelected(selected.toSet())
|
artistListAdapter.setSelected(selected.toSet())
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,8 @@ import org.oxycblt.auxio.list.Header
|
||||||
import org.oxycblt.auxio.list.Item
|
import org.oxycblt.auxio.list.Item
|
||||||
import org.oxycblt.auxio.list.ListFragment
|
import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.Sort
|
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.list.selection.SelectionViewModel
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
|
@ -70,6 +72,7 @@ class GenreDetailFragment :
|
||||||
DetailHeaderAdapter.Listener,
|
DetailHeaderAdapter.Listener,
|
||||||
DetailListAdapter.Listener<Music> {
|
DetailListAdapter.Listener<Music> {
|
||||||
override val detailModel: DetailViewModel by activityViewModels()
|
override val detailModel: DetailViewModel by activityViewModels()
|
||||||
|
private val menuModel: MenuViewModel by activityViewModels()
|
||||||
override val selectionModel: SelectionViewModel by activityViewModels()
|
override val selectionModel: SelectionViewModel by activityViewModels()
|
||||||
override val musicModel: MusicViewModel by activityViewModels()
|
override val musicModel: MusicViewModel by activityViewModels()
|
||||||
override val playbackModel: PlaybackViewModel by activityViewModels()
|
override val playbackModel: PlaybackViewModel by activityViewModels()
|
||||||
|
@ -123,6 +126,7 @@ class GenreDetailFragment :
|
||||||
collectImmediately(detailModel.currentGenre, ::updatePlaylist)
|
collectImmediately(detailModel.currentGenre, ::updatePlaylist)
|
||||||
collectImmediately(detailModel.genreList, ::updateList)
|
collectImmediately(detailModel.genreList, ::updateList)
|
||||||
collect(detailModel.toShow.flow, ::handleShow)
|
collect(detailModel.toShow.flow, ::handleShow)
|
||||||
|
collect(menuModel.pendingMenu.flow, ::handleMenu)
|
||||||
collectImmediately(selectionModel.selected, ::updateSelection)
|
collectImmediately(selectionModel.selected, ::updateSelection)
|
||||||
collect(musicModel.playlistDecision.flow, ::handleDecision)
|
collect(musicModel.playlistDecision.flow, ::handleDecision)
|
||||||
collectImmediately(
|
collectImmediately(
|
||||||
|
@ -192,8 +196,8 @@ class GenreDetailFragment :
|
||||||
|
|
||||||
override fun onOpenMenu(item: Music, anchor: View) {
|
override fun onOpenMenu(item: Music, anchor: View) {
|
||||||
when (item) {
|
when (item) {
|
||||||
is Artist -> openMusicMenu(anchor, R.menu.item_parent, item)
|
is Artist -> menuModel.openMenu(R.menu.item_parent, item)
|
||||||
is Song -> openMusicMenu(anchor, R.menu.item_song, item)
|
is Song -> menuModel.openMenu(R.menu.item_song, item)
|
||||||
else -> error("Unexpected datatype: ${item::class.simpleName}")
|
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<Music>) {
|
private fun updateSelection(selected: List<Music>) {
|
||||||
genreListAdapter.setSelected(selected.toSet())
|
genreListAdapter.setSelected(selected.toSet())
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,8 @@ import org.oxycblt.auxio.list.Divider
|
||||||
import org.oxycblt.auxio.list.Header
|
import org.oxycblt.auxio.list.Header
|
||||||
import org.oxycblt.auxio.list.Item
|
import org.oxycblt.auxio.list.Item
|
||||||
import org.oxycblt.auxio.list.ListFragment
|
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.list.selection.SelectionViewModel
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
import org.oxycblt.auxio.music.MusicParent
|
import org.oxycblt.auxio.music.MusicParent
|
||||||
|
@ -73,6 +75,7 @@ class PlaylistDetailFragment :
|
||||||
PlaylistDetailListAdapter.Listener,
|
PlaylistDetailListAdapter.Listener,
|
||||||
NavController.OnDestinationChangedListener {
|
NavController.OnDestinationChangedListener {
|
||||||
override val detailModel: DetailViewModel by activityViewModels()
|
override val detailModel: DetailViewModel by activityViewModels()
|
||||||
|
private val menuModel: MenuViewModel by activityViewModels()
|
||||||
override val selectionModel: SelectionViewModel by activityViewModels()
|
override val selectionModel: SelectionViewModel by activityViewModels()
|
||||||
override val musicModel: MusicViewModel by activityViewModels()
|
override val musicModel: MusicViewModel by activityViewModels()
|
||||||
override val playbackModel: PlaybackViewModel by activityViewModels()
|
override val playbackModel: PlaybackViewModel by activityViewModels()
|
||||||
|
@ -138,6 +141,7 @@ class PlaylistDetailFragment :
|
||||||
collectImmediately(detailModel.playlistList, ::updateList)
|
collectImmediately(detailModel.playlistList, ::updateList)
|
||||||
collectImmediately(detailModel.editedPlaylist, ::updateEditedList)
|
collectImmediately(detailModel.editedPlaylist, ::updateEditedList)
|
||||||
collect(detailModel.toShow.flow, ::handleShow)
|
collect(detailModel.toShow.flow, ::handleShow)
|
||||||
|
collect(menuModel.pendingMenu.flow, ::handleMenu)
|
||||||
collectImmediately(selectionModel.selected, ::updateSelection)
|
collectImmediately(selectionModel.selected, ::updateSelection)
|
||||||
collect(musicModel.playlistDecision.flow, ::handleDecision)
|
collect(musicModel.playlistDecision.flow, ::handleDecision)
|
||||||
collectImmediately(
|
collectImmediately(
|
||||||
|
@ -235,7 +239,7 @@ class PlaylistDetailFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOpenMenu(item: Song, anchor: View) {
|
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() {
|
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<Music>) {
|
private fun updateSelection(selected: List<Music>) {
|
||||||
playlistListAdapter.setSelected(selected.toSet())
|
playlistListAdapter.setSelected(selected.toSet())
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,8 @@ import org.oxycblt.auxio.home.list.SongListFragment
|
||||||
import org.oxycblt.auxio.home.tabs.AdaptiveTabStrategy
|
import org.oxycblt.auxio.home.tabs.AdaptiveTabStrategy
|
||||||
import org.oxycblt.auxio.home.tabs.Tab
|
import org.oxycblt.auxio.home.tabs.Tab
|
||||||
import org.oxycblt.auxio.list.Sort
|
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.SelectionFragment
|
||||||
import org.oxycblt.auxio.list.selection.SelectionViewModel
|
import org.oxycblt.auxio.list.selection.SelectionViewModel
|
||||||
import org.oxycblt.auxio.music.IndexingProgress
|
import org.oxycblt.auxio.music.IndexingProgress
|
||||||
|
@ -87,6 +89,7 @@ import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class HomeFragment :
|
class HomeFragment :
|
||||||
SelectionFragment<FragmentHomeBinding>(), AppBarLayout.OnOffsetChangedListener {
|
SelectionFragment<FragmentHomeBinding>(), AppBarLayout.OnOffsetChangedListener {
|
||||||
|
private val menuModel: MenuViewModel by activityViewModels()
|
||||||
override val selectionModel: SelectionViewModel by activityViewModels()
|
override val selectionModel: SelectionViewModel by activityViewModels()
|
||||||
override val musicModel: MusicViewModel by activityViewModels()
|
override val musicModel: MusicViewModel by activityViewModels()
|
||||||
override val playbackModel: PlaybackViewModel by activityViewModels()
|
override val playbackModel: PlaybackViewModel by activityViewModels()
|
||||||
|
@ -175,6 +178,7 @@ class HomeFragment :
|
||||||
collect(homeModel.recreateTabs.flow, ::handleRecreate)
|
collect(homeModel.recreateTabs.flow, ::handleRecreate)
|
||||||
collectImmediately(homeModel.currentTabMode, ::updateCurrentTab)
|
collectImmediately(homeModel.currentTabMode, ::updateCurrentTab)
|
||||||
collectImmediately(homeModel.songsList, homeModel.isFastScrolling, ::updateFab)
|
collectImmediately(homeModel.songsList, homeModel.isFastScrolling, ::updateFab)
|
||||||
|
collect(menuModel.pendingMenu.flow, ::handleMenu)
|
||||||
collectImmediately(selectionModel.selected, ::updateSelection)
|
collectImmediately(selectionModel.selected, ::updateSelection)
|
||||||
collectImmediately(musicModel.indexingState, ::updateIndexerState)
|
collectImmediately(musicModel.indexingState, ::updateIndexerState)
|
||||||
collect(musicModel.playlistDecision.flow, ::handleDecision)
|
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<Music>) {
|
private fun updateSelection(selected: List<Music>) {
|
||||||
val binding = requireBinding()
|
val binding = requireBinding()
|
||||||
if (selected.isNotEmpty()) {
|
if (selected.isNotEmpty()) {
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.SelectableListListener
|
import org.oxycblt.auxio.list.SelectableListListener
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.Sort
|
||||||
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
|
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.recycler.AlbumViewHolder
|
||||||
import org.oxycblt.auxio.list.selection.SelectionViewModel
|
import org.oxycblt.auxio.list.selection.SelectionViewModel
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
|
@ -60,9 +61,10 @@ class AlbumListFragment :
|
||||||
FastScrollRecyclerView.PopupProvider {
|
FastScrollRecyclerView.PopupProvider {
|
||||||
private val homeModel: HomeViewModel by activityViewModels()
|
private val homeModel: HomeViewModel by activityViewModels()
|
||||||
override val detailModel: DetailViewModel by activityViewModels()
|
override val detailModel: DetailViewModel by activityViewModels()
|
||||||
override val playbackModel: PlaybackViewModel by activityViewModels()
|
private val menuModel: MenuViewModel by activityViewModels()
|
||||||
override val musicModel: MusicViewModel by activityViewModels()
|
|
||||||
override val selectionModel: SelectionViewModel 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)
|
private val albumAdapter = AlbumAdapter(this)
|
||||||
// Save memory by re-using the same formatter and string builder when creating popup text
|
// Save memory by re-using the same formatter and string builder when creating popup text
|
||||||
private val formatterSb = StringBuilder(64)
|
private val formatterSb = StringBuilder(64)
|
||||||
|
|
|
@ -33,6 +33,7 @@ import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.SelectableListListener
|
import org.oxycblt.auxio.list.SelectableListListener
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.Sort
|
||||||
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
|
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.recycler.ArtistViewHolder
|
||||||
import org.oxycblt.auxio.list.selection.SelectionViewModel
|
import org.oxycblt.auxio.list.selection.SelectionViewModel
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
|
@ -58,9 +59,10 @@ class ArtistListFragment :
|
||||||
FastScrollRecyclerView.Listener {
|
FastScrollRecyclerView.Listener {
|
||||||
private val homeModel: HomeViewModel by activityViewModels()
|
private val homeModel: HomeViewModel by activityViewModels()
|
||||||
override val detailModel: DetailViewModel by activityViewModels()
|
override val detailModel: DetailViewModel by activityViewModels()
|
||||||
override val playbackModel: PlaybackViewModel by activityViewModels()
|
private val menuModel: MenuViewModel by activityViewModels()
|
||||||
override val musicModel: MusicViewModel by activityViewModels()
|
|
||||||
override val selectionModel: SelectionViewModel 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)
|
private val artistAdapter = ArtistAdapter(this)
|
||||||
|
|
||||||
override fun onCreateBinding(inflater: LayoutInflater) =
|
override fun onCreateBinding(inflater: LayoutInflater) =
|
||||||
|
@ -118,7 +120,7 @@ class ArtistListFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOpenMenu(item: Artist, anchor: View) {
|
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<Artist>) {
|
private fun updateArtists(artists: List<Artist>) {
|
||||||
|
|
|
@ -33,6 +33,7 @@ import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.SelectableListListener
|
import org.oxycblt.auxio.list.SelectableListListener
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.Sort
|
||||||
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
|
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.recycler.GenreViewHolder
|
||||||
import org.oxycblt.auxio.list.selection.SelectionViewModel
|
import org.oxycblt.auxio.list.selection.SelectionViewModel
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
|
@ -57,9 +58,10 @@ class GenreListFragment :
|
||||||
FastScrollRecyclerView.Listener {
|
FastScrollRecyclerView.Listener {
|
||||||
private val homeModel: HomeViewModel by activityViewModels()
|
private val homeModel: HomeViewModel by activityViewModels()
|
||||||
override val detailModel: DetailViewModel by activityViewModels()
|
override val detailModel: DetailViewModel by activityViewModels()
|
||||||
override val playbackModel: PlaybackViewModel by activityViewModels()
|
private val menuModel: MenuViewModel by activityViewModels()
|
||||||
override val musicModel: MusicViewModel by activityViewModels()
|
|
||||||
override val selectionModel: SelectionViewModel 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)
|
private val genreAdapter = GenreAdapter(this)
|
||||||
|
|
||||||
override fun onCreateBinding(inflater: LayoutInflater) =
|
override fun onCreateBinding(inflater: LayoutInflater) =
|
||||||
|
@ -117,7 +119,7 @@ class GenreListFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOpenMenu(item: Genre, anchor: View) {
|
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<Genre>) {
|
private fun updateGenres(genres: List<Genre>) {
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.SelectableListListener
|
import org.oxycblt.auxio.list.SelectableListListener
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.Sort
|
||||||
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
|
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.recycler.PlaylistViewHolder
|
||||||
import org.oxycblt.auxio.list.selection.SelectionViewModel
|
import org.oxycblt.auxio.list.selection.SelectionViewModel
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
|
@ -55,9 +56,10 @@ class PlaylistListFragment :
|
||||||
FastScrollRecyclerView.Listener {
|
FastScrollRecyclerView.Listener {
|
||||||
private val homeModel: HomeViewModel by activityViewModels()
|
private val homeModel: HomeViewModel by activityViewModels()
|
||||||
override val detailModel: DetailViewModel by activityViewModels()
|
override val detailModel: DetailViewModel by activityViewModels()
|
||||||
override val playbackModel: PlaybackViewModel by activityViewModels()
|
private val menuModel: MenuViewModel by activityViewModels()
|
||||||
override val musicModel: MusicViewModel by activityViewModels()
|
|
||||||
override val selectionModel: SelectionViewModel 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)
|
private val playlistAdapter = PlaylistAdapter(this)
|
||||||
|
|
||||||
override fun onCreateBinding(inflater: LayoutInflater) =
|
override fun onCreateBinding(inflater: LayoutInflater) =
|
||||||
|
@ -115,7 +117,7 @@ class PlaylistListFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOpenMenu(item: Playlist, anchor: View) {
|
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<Playlist>) {
|
private fun updatePlaylists(playlists: List<Playlist>) {
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.SelectableListListener
|
import org.oxycblt.auxio.list.SelectableListListener
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.Sort
|
||||||
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
|
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.recycler.SongViewHolder
|
||||||
import org.oxycblt.auxio.list.selection.SelectionViewModel
|
import org.oxycblt.auxio.list.selection.SelectionViewModel
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
|
@ -59,9 +60,10 @@ class SongListFragment :
|
||||||
FastScrollRecyclerView.Listener {
|
FastScrollRecyclerView.Listener {
|
||||||
private val homeModel: HomeViewModel by activityViewModels()
|
private val homeModel: HomeViewModel by activityViewModels()
|
||||||
override val detailModel: DetailViewModel by activityViewModels()
|
override val detailModel: DetailViewModel by activityViewModels()
|
||||||
override val playbackModel: PlaybackViewModel by activityViewModels()
|
private val menuModel: MenuViewModel by activityViewModels()
|
||||||
override val musicModel: MusicViewModel by activityViewModels()
|
|
||||||
override val selectionModel: SelectionViewModel 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)
|
private val songAdapter = SongAdapter(this)
|
||||||
// Save memory by re-using the same formatter and string builder when creating popup text
|
// Save memory by re-using the same formatter and string builder when creating popup text
|
||||||
private val formatterSb = StringBuilder(64)
|
private val formatterSb = StringBuilder(64)
|
||||||
|
@ -143,7 +145,7 @@ class SongListFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOpenMenu(item: Song, anchor: View) {
|
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<Song>) {
|
private fun updateSongs(songs: List<Song>) {
|
||||||
|
|
|
@ -71,7 +71,7 @@ abstract class MenuDialogFragment<T : Music> :
|
||||||
menuAdapter.update(builder.children.toList(), UpdateInstructions.Diff)
|
menuAdapter.update(builder.children.toList(), UpdateInstructions.Diff)
|
||||||
|
|
||||||
// --- VIEWMODEL SETUP ---
|
// --- VIEWMODEL SETUP ---
|
||||||
menuModel.setMusic(uid)
|
menuModel.setCurrentMenu(uid)
|
||||||
collectImmediately(menuModel.currentMusic, this::updateMusic)
|
collectImmediately(menuModel.currentMusic, this::updateMusic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
package org.oxycblt.auxio.list.menu
|
package org.oxycblt.auxio.list.menu
|
||||||
|
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
|
@ -34,7 +34,7 @@ import org.oxycblt.auxio.util.getPlural
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class SongMenuDialogFragment : MenuDialogFragment<Song>() {
|
class SongMenuDialogFragment : MenuDialogFragment<Song>() {
|
||||||
override val menuModel: MenuViewModel by viewModels()
|
override val menuModel: MenuViewModel by activityViewModels()
|
||||||
private val args: SongMenuDialogFragmentArgs by navArgs()
|
private val args: SongMenuDialogFragmentArgs by navArgs()
|
||||||
|
|
||||||
override val menuRes: Int
|
override val menuRes: Int
|
||||||
|
@ -55,7 +55,7 @@ class SongMenuDialogFragment : MenuDialogFragment<Song>() {
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class AlbumMenuDialogFragment : MenuDialogFragment<Album>() {
|
class AlbumMenuDialogFragment : MenuDialogFragment<Album>() {
|
||||||
override val menuModel: MenuViewModel by viewModels()
|
override val menuModel: MenuViewModel by activityViewModels()
|
||||||
private val args: AlbumMenuDialogFragmentArgs by navArgs()
|
private val args: AlbumMenuDialogFragmentArgs by navArgs()
|
||||||
|
|
||||||
override val menuRes: Int
|
override val menuRes: Int
|
||||||
|
@ -76,7 +76,7 @@ class AlbumMenuDialogFragment : MenuDialogFragment<Album>() {
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class ArtistMenuDialogFragment : MenuDialogFragment<Artist>() {
|
class ArtistMenuDialogFragment : MenuDialogFragment<Artist>() {
|
||||||
override val menuModel: MenuViewModel by viewModels()
|
override val menuModel: MenuViewModel by activityViewModels()
|
||||||
private val args: ArtistMenuDialogFragmentArgs by navArgs()
|
private val args: ArtistMenuDialogFragmentArgs by navArgs()
|
||||||
|
|
||||||
override val menuRes: Int
|
override val menuRes: Int
|
||||||
|
@ -105,7 +105,7 @@ class ArtistMenuDialogFragment : MenuDialogFragment<Artist>() {
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class GenreMenuDialogFragment : MenuDialogFragment<Genre>() {
|
class GenreMenuDialogFragment : MenuDialogFragment<Genre>() {
|
||||||
override val menuModel: MenuViewModel by viewModels()
|
override val menuModel: MenuViewModel by activityViewModels()
|
||||||
private val args: GenreMenuDialogFragmentArgs by navArgs()
|
private val args: GenreMenuDialogFragmentArgs by navArgs()
|
||||||
|
|
||||||
override val menuRes: Int
|
override val menuRes: Int
|
||||||
|
@ -130,7 +130,7 @@ class GenreMenuDialogFragment : MenuDialogFragment<Genre>() {
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class PlaylistMenuDialogFragment : MenuDialogFragment<Playlist>() {
|
class PlaylistMenuDialogFragment : MenuDialogFragment<Playlist>() {
|
||||||
override val menuModel: MenuViewModel by viewModels()
|
override val menuModel: MenuViewModel by activityViewModels()
|
||||||
private val args: PlaylistMenuDialogFragmentArgs by navArgs()
|
private val args: PlaylistMenuDialogFragmentArgs by navArgs()
|
||||||
|
|
||||||
override val menuRes: Int
|
override val menuRes: Int
|
||||||
|
|
|
@ -18,18 +18,29 @@
|
||||||
|
|
||||||
package org.oxycblt.auxio.list.menu
|
package org.oxycblt.auxio.list.menu
|
||||||
|
|
||||||
|
import androidx.annotation.MenuRes
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
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.Album
|
||||||
|
import org.oxycblt.auxio.music.Artist
|
||||||
|
import org.oxycblt.auxio.music.Genre
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
import org.oxycblt.auxio.music.MusicRepository
|
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
|
import org.oxycblt.auxio.util.logW
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class MenuViewModel @Inject constructor(private val musicRepository: MusicRepository) :
|
class MenuViewModel @Inject constructor(private val musicRepository: MusicRepository) :
|
||||||
ViewModel(), MusicRepository.UpdateListener {
|
ViewModel(), MusicRepository.UpdateListener {
|
||||||
|
private val _pendingMenu = MutableEvent<PendingMenu>()
|
||||||
|
val pendingMenu: Event<PendingMenu> = _pendingMenu
|
||||||
|
|
||||||
private val _currentMusic = MutableStateFlow<Music?>(null)
|
private val _currentMusic = MutableStateFlow<Music?>(null)
|
||||||
val currentMusic: StateFlow<Music?> = _currentMusic
|
val currentMusic: StateFlow<Music?> = _currentMusic
|
||||||
|
|
||||||
|
@ -45,10 +56,46 @@ class MenuViewModel @Inject constructor(private val musicRepository: MusicReposi
|
||||||
musicRepository.removeUpdateListener(this)
|
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)
|
_currentMusic.value = musicRepository.find(uid)
|
||||||
if (_currentMusic.value == null) {
|
if (_currentMusic.value == null) {
|
||||||
logW("Given Music UID to show was invalid")
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -36,11 +36,12 @@ import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.FragmentSearchBinding
|
import org.oxycblt.auxio.databinding.FragmentSearchBinding
|
||||||
import org.oxycblt.auxio.detail.DetailViewModel
|
import org.oxycblt.auxio.detail.DetailViewModel
|
||||||
import org.oxycblt.auxio.detail.Show
|
import org.oxycblt.auxio.detail.Show
|
||||||
import org.oxycblt.auxio.home.HomeFragmentDirections
|
|
||||||
import org.oxycblt.auxio.list.Divider
|
import org.oxycblt.auxio.list.Divider
|
||||||
import org.oxycblt.auxio.list.Header
|
import org.oxycblt.auxio.list.Header
|
||||||
import org.oxycblt.auxio.list.Item
|
import org.oxycblt.auxio.list.Item
|
||||||
import org.oxycblt.auxio.list.ListFragment
|
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.list.selection.SelectionViewModel
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
|
@ -71,9 +72,10 @@ import org.oxycblt.auxio.util.setFullWidthLookup
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
||||||
override val detailModel: DetailViewModel by activityViewModels()
|
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 playbackModel: PlaybackViewModel by activityViewModels()
|
||||||
override val musicModel: MusicViewModel by activityViewModels()
|
override val musicModel: MusicViewModel by activityViewModels()
|
||||||
override val selectionModel: SelectionViewModel by activityViewModels()
|
|
||||||
private val searchModel: SearchViewModel by viewModels()
|
private val searchModel: SearchViewModel by viewModels()
|
||||||
private val searchAdapter = SearchAdapter(this)
|
private val searchAdapter = SearchAdapter(this)
|
||||||
private var imm: InputMethodManager? = null
|
private var imm: InputMethodManager? = null
|
||||||
|
@ -138,6 +140,7 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
||||||
// --- VIEWMODEL SETUP ---
|
// --- VIEWMODEL SETUP ---
|
||||||
|
|
||||||
collectImmediately(searchModel.searchResults, ::updateSearchResults)
|
collectImmediately(searchModel.searchResults, ::updateSearchResults)
|
||||||
|
collect(menuModel.pendingMenu.flow, ::handleMenu)
|
||||||
collectImmediately(selectionModel.selected, ::updateSelection)
|
collectImmediately(selectionModel.selected, ::updateSelection)
|
||||||
collect(musicModel.playlistDecision.flow, ::handleDecision)
|
collect(musicModel.playlistDecision.flow, ::handleDecision)
|
||||||
collectImmediately(
|
collectImmediately(
|
||||||
|
@ -181,11 +184,11 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
||||||
|
|
||||||
override fun onOpenMenu(item: Music, anchor: View) {
|
override fun onOpenMenu(item: Music, anchor: View) {
|
||||||
when (item) {
|
when (item) {
|
||||||
is Song -> openMusicMenu(anchor, R.menu.item_song, item)
|
is Song -> menuModel.openMenu(R.menu.item_song, item)
|
||||||
is Album -> openMusicMenu(anchor, R.menu.item_album, item)
|
is Album -> menuModel.openMenu(R.menu.item_album, item)
|
||||||
is Artist -> openMusicMenu(anchor, R.menu.item_parent, item)
|
is Artist -> menuModel.openMenu(R.menu.item_parent, item)
|
||||||
is Genre -> openMusicMenu(anchor, R.menu.item_parent, item)
|
is Genre -> menuModel.openMenu(R.menu.item_parent, item)
|
||||||
is Playlist -> openMusicMenu(anchor, R.menu.item_playlist, item)
|
is Playlist -> menuModel.openMenu(R.menu.item_playlist, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +250,7 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
||||||
is Show.PlaylistDetails -> {
|
is Show.PlaylistDetails -> {
|
||||||
logD("Navigating to ${show.playlist}")
|
logD("Navigating to ${show.playlist}")
|
||||||
findNavController()
|
findNavController()
|
||||||
.navigateSafe(SearchFragmentDirections.showGenre(show.playlist.uid))
|
.navigateSafe(SearchFragmentDirections.showPlaylist(show.playlist.uid))
|
||||||
}
|
}
|
||||||
null -> {}
|
null -> {}
|
||||||
}
|
}
|
||||||
|
@ -258,32 +261,26 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
||||||
|
|
||||||
private fun handleDecision(decision: PlaylistDecision?) {
|
private fun handleDecision(decision: PlaylistDecision?) {
|
||||||
if (decision == null) return
|
if (decision == null) return
|
||||||
|
val directions =
|
||||||
when (decision) {
|
when (decision) {
|
||||||
is PlaylistDecision.New -> {
|
|
||||||
logD("Creating new playlist")
|
|
||||||
findNavController()
|
|
||||||
.navigateSafe(
|
|
||||||
HomeFragmentDirections.newPlaylist(
|
|
||||||
decision.songs.map { it.uid }.toTypedArray()))
|
|
||||||
}
|
|
||||||
is PlaylistDecision.Rename -> {
|
is PlaylistDecision.Rename -> {
|
||||||
logD("Renaming ${decision.playlist}")
|
logD("Renaming ${decision.playlist}")
|
||||||
findNavController()
|
SearchFragmentDirections.renamePlaylist(decision.playlist.uid)
|
||||||
.navigateSafe(HomeFragmentDirections.renamePlaylist(decision.playlist.uid))
|
|
||||||
}
|
}
|
||||||
is PlaylistDecision.Delete -> {
|
is PlaylistDecision.Delete -> {
|
||||||
logD("Deleting ${decision.playlist}")
|
logD("Deleting ${decision.playlist}")
|
||||||
findNavController()
|
SearchFragmentDirections.deletePlaylist(decision.playlist.uid)
|
||||||
.navigateSafe(SearchFragmentDirections.deletePlaylist(decision.playlist.uid))
|
|
||||||
}
|
}
|
||||||
is PlaylistDecision.Add -> {
|
is PlaylistDecision.Add -> {
|
||||||
logD("Adding ${decision.songs.size} to a playlist")
|
logD("Adding ${decision.songs.size} to a playlist")
|
||||||
findNavController()
|
SearchFragmentDirections.addToPlaylist(
|
||||||
.navigateSafe(
|
decision.songs.map { it.uid }.toTypedArray())
|
||||||
HomeFragmentDirections.addToPlaylist(
|
}
|
||||||
decision.songs.map { it.uid }.toTypedArray()))
|
is PlaylistDecision.New -> {
|
||||||
|
error("Unexpected decision $decision")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
findNavController().navigateSafe(directions)
|
||||||
musicModel.playlistDecision.consume()
|
musicModel.playlistDecision.consume()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,6 +288,30 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
||||||
searchAdapter.setPlaying(parent ?: song, isPlaying)
|
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<Music>) {
|
private fun updateSelection(selected: List<Music>) {
|
||||||
searchAdapter.setSelected(selected.toSet())
|
searchAdapter.setSelected(selected.toSet())
|
||||||
val binding = requireBinding()
|
val binding = requireBinding()
|
||||||
|
|
|
@ -2,26 +2,28 @@
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
style="@style/Widget.Auxio.RecyclerView.Linear"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<org.oxycblt.auxio.image.CoverView
|
<org.oxycblt.auxio.image.CoverView
|
||||||
android:id="@+id/menu_cover"
|
android:id="@+id/menu_cover"
|
||||||
style="@style/Widget.Auxio.Image.MidLarge"
|
style="@style/Widget.Auxio.Image.Full"
|
||||||
android:layout_margin="@dimen/spacing_medium"
|
android:layout_marginVertical="@dimen/spacing_medium"
|
||||||
|
android:layout_marginStart="@dimen/spacing_medium"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/menu_type"
|
android:id="@+id/menu_type"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="@style/TextAppearance.Auxio.LabelLarge"
|
android:layout_marginHorizontal="@dimen/spacing_medium"
|
||||||
|
android:layout_marginTop="@dimen/spacing_small"
|
||||||
|
android:textAppearance="@style/TextAppearance.Auxio.LabelMedium"
|
||||||
android:textColor="?attr/colorSecondary"
|
android:textColor="?attr/colorSecondary"
|
||||||
android:layout_marginStart="@dimen/spacing_medium"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/menu_name"
|
app:layout_constraintBottom_toTopOf="@+id/menu_name"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@+id/menu_cover"
|
app:layout_constraintStart_toEndOf="@+id/menu_cover"
|
||||||
app:layout_constraintTop_toTopOf="@+id/menu_cover"
|
app:layout_constraintTop_toTopOf="@+id/menu_cover"
|
||||||
app:layout_constraintVertical_chainStyle="packed"
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
|
@ -29,32 +31,42 @@
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/menu_name"
|
android:id="@+id/menu_name"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="@style/TextAppearance.Auxio.TitleLarge"
|
style="@style/Widget.Auxio.TextView.Primary"
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/menu_info"
|
app:layout_constraintBottom_toTopOf="@+id/menu_info"
|
||||||
|
app:layout_constraintEnd_toEndOf="@+id/menu_type"
|
||||||
app:layout_constraintStart_toStartOf="@+id/menu_type"
|
app:layout_constraintStart_toStartOf="@+id/menu_type"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/menu_type"
|
app:layout_constraintTop_toBottomOf="@+id/menu_type"
|
||||||
tools:text="Name" />
|
tools:text="Name" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/menu_info"
|
android:id="@+id/menu_info"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="@style/TextAppearance.Auxio.TitleMedium"
|
style="@style/Widget.Auxio.TextView.Secondary.Marquee"
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/menu_cover"
|
app:layout_constraintEnd_toEndOf="@+id/menu_type"
|
||||||
app:layout_constraintStart_toStartOf="@+id/menu_name"
|
app:layout_constraintStart_toStartOf="@+id/menu_name"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/menu_name"
|
app:layout_constraintTop_toBottomOf="@+id/menu_name"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@+id/menu_cover"
|
||||||
|
android:layout_marginBottom="@dimen/spacing_small"
|
||||||
tools:text="Info A" />
|
tools:text="Info A" />
|
||||||
|
|
||||||
<org.oxycblt.auxio.list.recycler.DialogRecyclerView
|
<com.google.android.material.divider.MaterialDivider
|
||||||
|
android:id="@+id/materialDivider"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/spacing_medium"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/menu_cover" />
|
||||||
|
|
||||||
|
<org.oxycblt.auxio.list.recycler.AuxioRecyclerView
|
||||||
android:id="@+id/menu_option_recycler"
|
android:id="@+id/menu_option_recycler"
|
||||||
style="@style/Widget.Auxio.RecyclerView.Linear"
|
style="@style/Widget.Auxio.RecyclerView.Linear"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/menu_cover"
|
android:overScrollMode="never"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/materialDivider"
|
||||||
tools:listitem="@layout/item_menu_option" />
|
tools:listitem="@layout/item_menu_option" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -33,6 +33,21 @@
|
||||||
<action
|
<action
|
||||||
android:id="@+id/show_playlist"
|
android:id="@+id/show_playlist"
|
||||||
app:destination="@id/playlist_detail_fragment" />
|
app:destination="@id/playlist_detail_fragment" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/open_song_menu"
|
||||||
|
app:destination="@id/song_menu_dialog" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/open_album_menu"
|
||||||
|
app:destination="@id/album_menu_dialog" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/open_artist_menu"
|
||||||
|
app:destination="@id/artist_menu_dialog" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/open_genre_menu"
|
||||||
|
app:destination="@id/genre_menu_dialog" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/open_playlist_menu"
|
||||||
|
app:destination="@id/playlist_menu_dialog" />
|
||||||
<action
|
<action
|
||||||
android:id="@+id/new_playlist"
|
android:id="@+id/new_playlist"
|
||||||
app:destination="@id/new_playlist_dialog" />
|
app:destination="@id/new_playlist_dialog" />
|
||||||
|
@ -86,6 +101,21 @@
|
||||||
<action
|
<action
|
||||||
android:id="@+id/show_playlist"
|
android:id="@+id/show_playlist"
|
||||||
app:destination="@id/playlist_detail_fragment" />
|
app:destination="@id/playlist_detail_fragment" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/open_song_menu"
|
||||||
|
app:destination="@id/song_menu_dialog" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/open_album_menu"
|
||||||
|
app:destination="@id/album_menu_dialog" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/open_artist_menu"
|
||||||
|
app:destination="@id/artist_menu_dialog" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/open_genre_menu"
|
||||||
|
app:destination="@id/genre_menu_dialog" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/open_playlist_menu"
|
||||||
|
app:destination="@id/playlist_menu_dialog" />
|
||||||
<action
|
<action
|
||||||
android:id="@+id/rename_playlist"
|
android:id="@+id/rename_playlist"
|
||||||
app:destination="@id/rename_playlist_dialog" />
|
app:destination="@id/rename_playlist_dialog" />
|
||||||
|
@ -123,12 +153,15 @@
|
||||||
<action
|
<action
|
||||||
android:id="@+id/show_artist"
|
android:id="@+id/show_artist"
|
||||||
app:destination="@id/artist_detail_fragment" />
|
app:destination="@id/artist_detail_fragment" />
|
||||||
<action
|
|
||||||
android:id="@+id/add_to_playlist"
|
|
||||||
app:destination="@id/add_to_playlist_dialog" />
|
|
||||||
<action
|
<action
|
||||||
android:id="@+id/show_artists"
|
android:id="@+id/show_artists"
|
||||||
app:destination="@id/show_artists_dialog" />
|
app:destination="@id/show_artists_dialog" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/open_song_menu"
|
||||||
|
app:destination="@id/song_menu_dialog" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/add_to_playlist"
|
||||||
|
app:destination="@id/add_to_playlist_dialog" />
|
||||||
<action
|
<action
|
||||||
android:id="@+id/play_from_artist"
|
android:id="@+id/play_from_artist"
|
||||||
app:destination="@id/play_from_artist_dialog" />
|
app:destination="@id/play_from_artist_dialog" />
|
||||||
|
@ -154,6 +187,12 @@
|
||||||
<action
|
<action
|
||||||
android:id="@+id/show_artist"
|
android:id="@+id/show_artist"
|
||||||
app:destination="@id/artist_detail_fragment" />
|
app:destination="@id/artist_detail_fragment" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/open_song_menu"
|
||||||
|
app:destination="@id/song_menu_dialog" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/open_album_menu"
|
||||||
|
app:destination="@id/album_menu_dialog" />
|
||||||
<action
|
<action
|
||||||
android:id="@+id/add_to_playlist"
|
android:id="@+id/add_to_playlist"
|
||||||
app:destination="@id/add_to_playlist_dialog" />
|
app:destination="@id/add_to_playlist_dialog" />
|
||||||
|
@ -182,6 +221,12 @@
|
||||||
<action
|
<action
|
||||||
android:id="@+id/show_artists"
|
android:id="@+id/show_artists"
|
||||||
app:destination="@id/show_artists_dialog" />
|
app:destination="@id/show_artists_dialog" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/open_song_menu"
|
||||||
|
app:destination="@id/song_menu_dialog" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/open_artist_menu"
|
||||||
|
app:destination="@id/artist_menu_dialog" />
|
||||||
<action
|
<action
|
||||||
android:id="@+id/add_to_playlist"
|
android:id="@+id/add_to_playlist"
|
||||||
app:destination="@id/add_to_playlist_dialog" />
|
app:destination="@id/add_to_playlist_dialog" />
|
||||||
|
@ -210,6 +255,9 @@
|
||||||
<action
|
<action
|
||||||
android:id="@+id/show_artists"
|
android:id="@+id/show_artists"
|
||||||
app:destination="@id/show_artists_dialog" />
|
app:destination="@id/show_artists_dialog" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/open_song_menu"
|
||||||
|
app:destination="@id/song_menu_dialog" />
|
||||||
<action
|
<action
|
||||||
android:id="@+id/rename_playlist"
|
android:id="@+id/rename_playlist"
|
||||||
app:destination="@id/rename_playlist_dialog" />
|
app:destination="@id/rename_playlist_dialog" />
|
||||||
|
|
Loading…
Reference in a new issue