From 51a5e9fd63f7a4ed743ec94c53c79104e59aac4b Mon Sep 17 00:00:00 2001 From: OxygenCobalt Date: Mon, 21 Dec 2020 20:10:38 -0700 Subject: [PATCH] Refactor genre UI Fully refactor the genre UI so that it makes more sense. --- .../auxio/detail/ArtistDetailFragment.kt | 3 +- .../auxio/detail/GenreDetailFragment.kt | 11 +---- .../java/org/oxycblt/auxio/music/Models.kt | 12 ++--- .../org/oxycblt/auxio/music/MusicUtils.kt | 31 ------------ .../auxio/music/processing/MusicLoader.kt | 14 ++++-- .../auxio/music/processing/MusicSorter.kt | 5 +- .../playback/state/PlaybackStateManager.kt | 8 ++-- .../oxycblt/auxio/settings/SettingsManager.kt | 1 + .../org/oxycblt/auxio/ui/InterfaceUtils.kt | 47 +++++++++++++++---- .../res/layout-land/fragment_album_detail.xml | 2 +- .../layout-land/fragment_artist_detail.xml | 2 +- .../res/layout-land/fragment_genre_detail.xml | 18 +++---- .../main/res/layout/fragment_album_detail.xml | 2 +- .../res/layout/fragment_artist_detail.xml | 2 +- .../main/res/layout/fragment_genre_detail.xml | 34 +++++++------- app/src/main/res/layout/item_genre.xml | 4 +- ...lbum_actions.xml => menu_album_detail.xml} | 0 ...menu_detail.xml => menu_artist_detail.xml} | 4 +- .../main/res/menu/menu_genre_song_actions.xml | 15 ++++++ app/src/main/res/values/strings.xml | 2 + 20 files changed, 116 insertions(+), 101 deletions(-) rename app/src/main/res/menu/{menu_album_actions.xml => menu_album_detail.xml} (100%) rename app/src/main/res/menu/{menu_detail.xml => menu_artist_detail.xml} (82%) create mode 100644 app/src/main/res/menu/menu_genre_song_actions.xml 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 1a369246e..f2df44d13 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt @@ -84,7 +84,8 @@ class ArtistDetailFragment : DetailFragment() { true } - R.id.action_play -> { + + R.id.action_play_albums -> { playbackModel.playArtist( detailModel.currentArtist.value!!, false ) 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 591355e21..b2be70cac 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt @@ -16,7 +16,7 @@ import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.state.PlaybackMode import org.oxycblt.auxio.ui.disable -import org.oxycblt.auxio.ui.setupSongActions +import org.oxycblt.auxio.ui.setupGenreSongActions /** * The [DetailFragment] for a genre. @@ -51,7 +51,7 @@ class GenreDetailFragment : DetailFragment() { playbackModel.playSong(it, PlaybackMode.IN_GENRE) }, doOnLongClick = { data, view -> - PopupMenu(requireContext(), view).setupSongActions( + PopupMenu(requireContext(), view).setupGenreSongActions( requireContext(), data, playbackModel ) } @@ -78,13 +78,6 @@ class GenreDetailFragment : DetailFragment() { true } - R.id.action_play -> { - playbackModel.playGenre( - detailModel.currentGenre.value!!, false - ) - - true - } else -> false } diff --git a/app/src/main/java/org/oxycblt/auxio/music/Models.kt b/app/src/main/java/org/oxycblt/auxio/music/Models.kt index 213fb6210..1f5540cea 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/Models.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/Models.kt @@ -161,12 +161,12 @@ data class Genre( private val mSongs = mutableListOf() val songs: List get() = mSongs - val albumCount: Int by lazy { - songs.groupBy { it.album }.size - } - - val artistCount: Int by lazy { - songs.groupBy { it.album.artist }.size + val totalDuration: String by lazy { + var seconds: Long = 0 + songs.forEach { + seconds += it.seconds + } + seconds.toDuration() } fun addSong(song: Song) { diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt index ed52f1b92..42caf2c0f 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt @@ -105,37 +105,6 @@ fun Int.toYear(context: Context): String { // --- BINDING ADAPTERS --- -/** - * Bind the artist + album counts for a genre - */ -@BindingAdapter("genreCounts") -fun TextView.bindGenreCounts(genre: Genre) { - val artists = context.resources.getQuantityString( - R.plurals.format_artist_count, genre.artistCount, genre.artistCount - ) - val albums = context.resources.getQuantityString( - R.plurals.format_album_count, genre.albumCount, genre.albumCount - ) - - text = context.getString(R.string.format_double_counts, artists, albums) -} - -/** - * Bind the album + song counts for a genre - */ -@BindingAdapter("altGenreCounts") -fun TextView.bindAltGenreCounts(genre: Genre) { - val albums = context.resources.getQuantityString( - R.plurals.format_album_count, genre.albumCount, genre.albumCount - ) - - val songs = context.resources.getQuantityString( - R.plurals.format_song_count, genre.songs.size, genre.songs.size - ) - - text = context.getString(R.string.format_double_counts, albums, songs) -} - /** * Bind the most prominent artist genre */ diff --git a/app/src/main/java/org/oxycblt/auxio/music/processing/MusicLoader.kt b/app/src/main/java/org/oxycblt/auxio/music/processing/MusicLoader.kt index 3fe7c78e2..e86ed43e6 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/processing/MusicLoader.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/processing/MusicLoader.kt @@ -2,6 +2,7 @@ package org.oxycblt.auxio.music.processing import android.annotation.SuppressLint import android.app.Application +import android.provider.MediaStore import android.provider.MediaStore.Audio.Albums import android.provider.MediaStore.Audio.Genres import android.provider.MediaStore.Audio.Media @@ -16,7 +17,8 @@ import org.oxycblt.auxio.music.toAlbumArtURI import org.oxycblt.auxio.music.toNamedGenre /** - * Object that loads music from the filesystem. + * Class that loads/constructs [Genre]s, [Album]s, and [Song] objects from the filesystem + * Artists are constructed in [MusicSorter], as they are only really containers for [Album]s */ class MusicLoader(private val app: Application) { var genres = mutableListOf() @@ -117,10 +119,14 @@ class MusicLoader(private val app: Application) { while (cursor.moveToNext()) { val id = cursor.getLong(idIndex) val name = cursor.getString(nameIndex) ?: albumPlaceholder - val artistName = cursor.getString(artistIdIndex) ?: artistPlaceholder + var artistName = cursor.getString(artistIdIndex) ?: artistPlaceholder val year = cursor.getInt(yearIndex) val coverUri = id.toAlbumArtURI() + if (artistName == MediaStore.UNKNOWN_STRING) { + artistName = artistPlaceholder + } + albums.add( Album( id = id, name = name, artistName = artistName, @@ -192,9 +198,7 @@ class MusicLoader(private val app: Application) { for (genre in genres) { val songGenreCursor = resolver.query( Genres.Members.getContentUri("external", genre.id), - arrayOf( - Genres.Members._ID - ), + arrayOf(Genres.Members._ID), null, null, null ) diff --git a/app/src/main/java/org/oxycblt/auxio/music/processing/MusicSorter.kt b/app/src/main/java/org/oxycblt/auxio/music/processing/MusicSorter.kt index 51dacf033..b7e3cacff 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/processing/MusicSorter.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/processing/MusicSorter.kt @@ -1,10 +1,12 @@ package org.oxycblt.auxio.music.processing -import org.oxycblt.auxio.logD import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Song +/** + * Object responsible for creating [Artist]s from [Album]s and generally sorting everything. + */ class MusicSorter( val songs: MutableList, val albums: MutableList @@ -27,7 +29,6 @@ class MusicSorter( val groupedAlbums = albums.groupBy { it.artistName } groupedAlbums.forEach { - logD(it.key) artists.add( Artist(id = artists.size.toLong(), name = it.key, albums = it.value) ) diff --git a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt index de7111806..daf50c23f 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt @@ -507,15 +507,13 @@ class PlaybackStateManager private constructor() { * @param useLastSong (Optional, defaults to false) Whether to use the previous song for the index calculations caused by the above parameter. */ private fun genShuffle(keepSong: Boolean, useLastSong: Boolean = false) { - val newSeed = Random.Default.nextLong() + mShuffleSeed = Random.Default.nextLong() - logD("Shuffling queue with seed $newSeed") + logD("Shuffling queue with seed $mShuffleSeed") val lastSong = if (useLastSong) mQueue[mIndex] else mSong - mShuffleSeed = newSeed - - mQueue.shuffle(Random(newSeed)) + mQueue.shuffle(Random(mShuffleSeed)) mIndex = 0 // If specified, make the current song the first member of the queue. diff --git a/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt b/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt index 361251ae2..2d8b81474 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt @@ -10,6 +10,7 @@ import org.oxycblt.auxio.ui.ACCENTS /** * Wrapper around the [SharedPreferences] class that writes & reads values without a context. + * TODO: Add option to play song from genre, now that its possible * @author OxygenCobalt */ class SettingsManager private constructor(context: Context) : diff --git a/app/src/main/java/org/oxycblt/auxio/ui/InterfaceUtils.kt b/app/src/main/java/org/oxycblt/auxio/ui/InterfaceUtils.kt index 4bfb1408a..9c61e142c 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/InterfaceUtils.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/InterfaceUtils.kt @@ -197,7 +197,7 @@ fun PopupMenu.setupAlbumActions( else -> false } } - inflateAndShow(R.menu.menu_album_actions) + inflateAndShow(R.menu.menu_album_detail) } /** @@ -221,7 +221,7 @@ fun PopupMenu.setupArtistActions(artist: Artist, playbackModel: PlaybackViewMode else -> false } } - inflateAndShow(R.menu.menu_detail) + inflateAndShow(R.menu.menu_artist_detail) } /** @@ -232,11 +232,6 @@ fun PopupMenu.setupArtistActions(artist: Artist, playbackModel: PlaybackViewMode fun PopupMenu.setupGenreActions(genre: Genre, playbackModel: PlaybackViewModel) { setOnMenuItemClickListener { when (it.itemId) { - R.id.action_play -> { - playbackModel.playGenre(genre, false) - true - } - R.id.action_shuffle -> { playbackModel.playGenre(genre, true) true @@ -245,7 +240,43 @@ fun PopupMenu.setupGenreActions(genre: Genre, playbackModel: PlaybackViewModel) else -> false } } - inflateAndShow(R.menu.menu_detail) + inflateAndShow(R.menu.menu_artist_detail) +} + +/** + * Show actions for a song in a genre. + * @param context [Context] required + * @param song [Song] the menu should correspond to + * @param playbackModel [PlaybackViewModel] to dispatch actions to + */ +fun PopupMenu.setupGenreSongActions(context: Context, song: Song, playbackModel: PlaybackViewModel) { + setOnMenuItemClickListener { + when (it.itemId) { + R.id.action_queue_add -> { + playbackModel.addToUserQueue(song) + context.getString(R.string.label_queue_added).createToast(context) + true + } + + R.id.action_play_artist -> { + playbackModel.playSong(song, PlaybackMode.IN_ARTIST) + true + } + + R.id.action_play_album -> { + playbackModel.playSong(song, PlaybackMode.IN_ALBUM) + true + } + + R.id.action_play_all_songs -> { + playbackModel.playSong(song, PlaybackMode.ALL_SONGS) + true + } + + else -> false + } + } + inflateAndShow(R.menu.menu_genre_song_actions) } /** diff --git a/app/src/main/res/layout-land/fragment_album_detail.xml b/app/src/main/res/layout-land/fragment_album_detail.xml index 2be17bc5b..70dd928e8 100644 --- a/app/src/main/res/layout-land/fragment_album_detail.xml +++ b/app/src/main/res/layout-land/fragment_album_detail.xml @@ -29,7 +29,7 @@ style="@style/Toolbar.Style.Icon" android:background="?android:attr/windowBackground" android:elevation="@dimen/elevation_normal" - app:menu="@menu/menu_album_actions" + app:menu="@menu/menu_album_detail" app:title="@string/label_library" /> + app:layout_constraintTop_toBottomOf="@+id/genre_song_count" + tools:text="16:16" /> - - + + + app:layout_constraintTop_toBottomOf="@+id/genre_song_count" + tools:text="16:16" /> + app:layout_constraintTop_toBottomOf="@+id/genre_duration" /> + tools:text="40 Songs" /> \ No newline at end of file diff --git a/app/src/main/res/menu/menu_album_actions.xml b/app/src/main/res/menu/menu_album_detail.xml similarity index 100% rename from app/src/main/res/menu/menu_album_actions.xml rename to app/src/main/res/menu/menu_album_detail.xml diff --git a/app/src/main/res/menu/menu_detail.xml b/app/src/main/res/menu/menu_artist_detail.xml similarity index 82% rename from app/src/main/res/menu/menu_detail.xml rename to app/src/main/res/menu/menu_artist_detail.xml index 964c2565d..5d2d4f0bb 100644 --- a/app/src/main/res/menu/menu_detail.xml +++ b/app/src/main/res/menu/menu_artist_detail.xml @@ -7,8 +7,8 @@ android:title="@string/label_shuffle" app:showAsAction="ifRoom" /> \ No newline at end of file diff --git a/app/src/main/res/menu/menu_genre_song_actions.xml b/app/src/main/res/menu/menu_genre_song_actions.xml new file mode 100644 index 000000000..961d7635d --- /dev/null +++ b/app/src/main/res/menu/menu_genre_song_actions.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 20d861a66..68d1253df 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -28,6 +28,8 @@ Play from album Play from artist Go to artist + Play albums + Shuffle albums Queue Add to queue