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 0f4404f3c..2662cb589 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt @@ -121,13 +121,13 @@ class AlbumDetailFragment : Fragment() { } // Update the play button depending on the current playback status - // If the shown album is currently playing, set the button icon to the current isPlaying - // status, and then set its behavior to modify isPlaying. - // If the shown album isn't currently playing, set the button to Play and its behavior - // to start the playback of the album. + // If playing this album -> Make button show media controls + // If not playing this album -> Make button update playback to the artist private fun updatePlayButton(mode: PlaybackMode, binding: FragmentAlbumDetailBinding) { - playbackModel.currentSong.value?.let { song -> - if (mode == PlaybackMode.IN_ALBUM && song.album == detailModel.currentAlbum.value) { + playbackModel.currentParent.value?.let { parent -> + if (mode == PlaybackMode.IN_ALBUM && + parent.id == detailModel.currentAlbum.value!!.id + ) { if (playbackModel.isPlaying.value!!) { binding.albumPlay.setImageResource(R.drawable.ic_pause) } else { 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 875093e24..f9306a3e3 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt @@ -106,14 +106,12 @@ class ArtistDetailFragment : Fragment() { } // Update the play button depending on the current playback status - // If the shown artist is currently playing, set the button icon to the current isPlaying - // status, and then set its behavior to modify isPlaying. - // If the shown artist isn't currently playing, set the button to Play and its behavior - // to start the playback of the artist. + // If playing this artist -> Make button show media controls + // If not playing this artist -> Make button update playback to the artist private fun updatePlayButton(mode: PlaybackMode, binding: FragmentArtistDetailBinding) { - playbackModel.currentSong.value?.let { song -> + playbackModel.currentParent.value?.let { parent -> if (mode == PlaybackMode.IN_ARTIST && - song.album.artist == detailModel.currentArtist.value + parent.id == detailModel.currentArtist.value!!.id ) { if (playbackModel.isPlaying.value!!) { binding.artistPlay.setImageResource(R.drawable.ic_pause) 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 88f7ca594..587af7192 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt @@ -9,12 +9,9 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentGenreDetailBinding import org.oxycblt.auxio.detail.adapters.DetailArtistAdapter import org.oxycblt.auxio.music.MusicStore -import org.oxycblt.auxio.playback.PlaybackMode -import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.theme.applyDivider import org.oxycblt.auxio.theme.disable @@ -22,7 +19,6 @@ class GenreDetailFragment : Fragment() { private val args: GenreDetailFragmentArgs by navArgs() private val detailModel: DetailViewModel by activityViewModels() - private val playbackModel: PlaybackViewModel by activityViewModels() override fun onCreateView( inflater: LayoutInflater, @@ -57,7 +53,6 @@ class GenreDetailFragment : Fragment() { binding.lifecycleOwner = this binding.detailModel = detailModel - binding.playbackModel = playbackModel binding.genre = detailModel.currentGenre.value binding.genreToolbar.setNavigationOnClickListener { @@ -89,14 +84,6 @@ class GenreDetailFragment : Fragment() { ) } - playbackModel.currentMode.observe(viewLifecycleOwner) { - updatePlayButton(it, binding) - } - - playbackModel.isPlaying.observe(viewLifecycleOwner) { - updatePlayButton(playbackModel.currentMode.value!!, binding) - } - Log.d(this::class.simpleName, "Fragment created.") return binding.root @@ -107,27 +94,4 @@ class GenreDetailFragment : Fragment() { detailModel.updateNavigationStatus(false) } - - private fun updatePlayButton(mode: PlaybackMode, binding: FragmentGenreDetailBinding) { - if (mode == PlaybackMode.IN_GENRE && - detailModel.currentGenre.value == playbackModel.currentGenre.value - ) { - Log.d(this::class.simpleName, "Retard") - if (playbackModel.isPlaying.value!!) { - binding.genrePlay.setImageResource(R.drawable.ic_pause) - } else { - binding.genrePlay.setImageResource(R.drawable.ic_play) - } - - binding.genrePlay.setOnClickListener { - playbackModel.invertPlayingStatus() - } - } else { - binding.genrePlay.setImageResource(R.drawable.ic_play) - - binding.genrePlay.setOnClickListener { - playbackModel.play(detailModel.currentGenre.value!!, 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 be8c8447c..e6ab92753 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/Models.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/Models.kt @@ -31,7 +31,7 @@ data class Song( data class Album( override val id: Long = -1, override val name: String, - val artistName: String, + val artistId: Long = -1, val coverUri: Uri = Uri.EMPTY, val year: Int = 0 ) : BaseModel() { @@ -52,8 +52,7 @@ data class Album( // Artist data class Artist( override val id: Long = -1, - override var name: String, - val givenGenres: MutableList = mutableListOf() + override var name: String ) : BaseModel() { val albums = mutableListOf() val genres = mutableListOf() @@ -75,14 +74,6 @@ data class Artist( } return songs } - val genreSongs: MutableList - get() { - val songs = mutableListOf() - genres.forEach { - songs.addAll(it.songs) - } - return songs - } } // Genre @@ -109,14 +100,6 @@ data class Genre( } return num } - val songs: MutableList - get() { - val songs = mutableListOf() - artists.forEach { - songs.addAll(it.songs) - } - return songs - } } // Header [Used for search, nothing else] 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 932d1ed37..dfcbd9198 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 @@ -1,7 +1,7 @@ package org.oxycblt.auxio.music.processing import android.content.ContentResolver -import android.database.Cursor +import android.provider.MediaStore import android.provider.MediaStore.Audio.Albums import android.provider.MediaStore.Audio.Artists import android.provider.MediaStore.Audio.Genres @@ -32,11 +32,6 @@ class MusicLoader( var albums = mutableListOf() var songs = mutableListOf() - private var genreCursor: Cursor? = null - private var artistCursor: Cursor? = null - private var albumCursor: Cursor? = null - private var songCursor: Cursor? = null - val response: MusicLoaderResponse init { @@ -67,7 +62,7 @@ class MusicLoader( Log.d(this::class.simpleName, "Starting genre search...") // First, get a cursor for every genre in the android system - genreCursor = resolver.query( + val genreCursor = resolver.query( Genres.EXTERNAL_CONTENT_URI, arrayOf( Genres._ID, // 0 @@ -86,7 +81,7 @@ class MusicLoader( val id = cursor.getLong(idIndex) var name = cursor.getString(nameIndex) ?: genrePlaceholder - // If a genre is still in an old int-based format [Android formats it as "(INT)"], + // If a genre is still in an old int-based format [Android formats it as "(INT)"],mu // convert that to the corresponding ID3 genre. if (name.contains(Regex("[0123456789)]"))) { name = name.toNamedGenre() ?: genrePlaceholder @@ -111,42 +106,59 @@ class MusicLoader( private fun loadArtists() { Log.d(this::class.simpleName, "Starting artist search...") - // Iterate through the artists for each loaded genre, and then add the genre - // with the artist. - // This is only done because using GENRE_NAME for songs is broken and has been for years. + // Load all the artists + val artistCursor = resolver.query( + Artists.EXTERNAL_CONTENT_URI, + arrayOf( + Artists._ID, // 0 + Artists.ARTIST // 1 + ), + null, null, + Artists.DEFAULT_SORT_ORDER + ) + + artistCursor?.use { cursor -> + val idIndex = cursor.getColumnIndexOrThrow(Artists._ID) + val nameIndex = cursor.getColumnIndexOrThrow(Artists.ARTIST) + + while (cursor.moveToNext()) { + val id = cursor.getLong(idIndex) + var name = cursor.getString(nameIndex) + + if (name == null || name == MediaStore.UNKNOWN_STRING) { + name = artistPlaceholder + } + + Log.d(this::class.simpleName, id.toString()) + + artists.add( + Artist( + id, name + ) + ) + } + + cursor.close() + } + + // Then try to associate any genres with their respective artists. for (genre in genres) { - artistCursor = resolver.query( + val artistGenreCursor = resolver.query( Genres.Members.getContentUri("external", genre.id), arrayOf( - Artists._ID, // 0 - Artists.ARTIST // 1 + Genres.Members.ARTIST_ID ), - null, null, - Artists.DEFAULT_SORT_ORDER + null, null, null ) - artistCursor?.use { cursor -> - val idIndex = cursor.getColumnIndexOrThrow(Artists._ID) - val nameIndex = cursor.getColumnIndexOrThrow(Artists.ARTIST) + artistGenreCursor?.let { cursor -> + val idIndex = cursor.getColumnIndexOrThrow(Genres.Members.ARTIST_ID) while (cursor.moveToNext()) { val id = cursor.getLong(idIndex) - val name = cursor.getString(nameIndex) ?: artistPlaceholder - // If an artist has already been added [Which is very likely due to how genres - // are processed], add the genre to the existing artist instead of creating a - // new one. - val existingArtist = artists.find { it.name == name } - - if (existingArtist != null) { - existingArtist.givenGenres.add(genre) - } else { - artists.add( - Artist( - id, name, - mutableListOf(genre) - ) - ) + artists.filter { it.id == id }.forEach { + it.genres.add(genre) } } @@ -154,9 +166,8 @@ class MusicLoader( } } - // Remove dupes [Just in case] artists = artists.distinctBy { - it.name to it.givenGenres + it.name to it.genres }.toMutableList() Log.d( @@ -168,12 +179,12 @@ class MusicLoader( private fun loadAlbums() { Log.d(this::class.simpleName, "Starting album search...") - albumCursor = resolver.query( + val albumCursor = resolver.query( Albums.EXTERNAL_CONTENT_URI, arrayOf( Albums._ID, // 0 Albums.ALBUM, // 1 - Albums.ARTIST, // 2 + Albums.ARTIST_ID, // 2 Albums.FIRST_YEAR, // 3 ), @@ -184,20 +195,20 @@ class MusicLoader( albumCursor?.use { cursor -> val idIndex = cursor.getColumnIndexOrThrow(Albums._ID) val nameIndex = cursor.getColumnIndexOrThrow(Albums.ALBUM) - val artistIndex = cursor.getColumnIndexOrThrow(Albums.ARTIST) + val artistIdIndex = cursor.getColumnIndexOrThrow(Albums.ARTIST_ID) val yearIndex = cursor.getColumnIndexOrThrow(Albums.FIRST_YEAR) while (cursor.moveToNext()) { val id = cursor.getLong(idIndex) val name = cursor.getString(nameIndex) ?: albumPlaceholder - val artist = cursor.getString(artistIndex) ?: artistPlaceholder + val artistId = cursor.getLong(artistIdIndex) val year = cursor.getInt(yearIndex) val coverUri = id.toAlbumArtURI() albums.add( Album( - id, name, artist, + id, name, artistId, coverUri, year ) ) @@ -206,9 +217,8 @@ class MusicLoader( cursor.close() } - // Remove dupes albums = albums.distinctBy { - it.name to it.artistName to it.year to it.numSongs + it.name to it.artistId to it.year to it.numSongs }.toMutableList() Log.d( @@ -220,7 +230,7 @@ class MusicLoader( private fun loadSongs() { Log.d(this::class.simpleName, "Starting song search...") - songCursor = resolver.query( + val songCursor = resolver.query( Media.EXTERNAL_CONTENT_URI, arrayOf( Media._ID, // 0 @@ -260,7 +270,6 @@ class MusicLoader( cursor.close() } - // Remove dupes songs = songs.distinctBy { it.name to it.albumId to it.track to it.duration }.toMutableList() 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 ee660cf28..73dbe5ea2 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 @@ -51,8 +51,7 @@ class MusicSorter( if (unknownSongs.size > 0) { val unknownAlbum = Album( - name = albumPlaceholder, - artistName = artistPlaceholder + name = albumPlaceholder ) for (song in unknownSongs) { @@ -76,7 +75,7 @@ class MusicSorter( for (artist in artists) { // Find all albums that match the current artist name - val artistAlbums = albums.filter { it.artistName == artist.name } + val artistAlbums = albums.filter { it.artistId == artist.id } // Then add them to the artist, along with refreshing the amount of albums for (album in artistAlbums) { @@ -85,8 +84,9 @@ class MusicSorter( } // Then group the artist's genres and sort them by "Prominence" - // A.K.A Who has the most map entries - val groupedGenres = artist.givenGenres.groupBy { it.name } + // A.K.A Who has the most bugged duplicate genres + val groupedGenres = artist.genres.groupBy { it.name } + artist.genres.clear() groupedGenres.keys.sortedByDescending { key -> groupedGenres[key]?.size @@ -129,7 +129,7 @@ class MusicSorter( for (genre in genres) { // Find all artists that match the current genre val genreArtists = artists.filter { artist -> - artist.givenGenres.any { + artist.genres.any { it.name == genre.name } } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackMode.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackMode.kt index 4d7cf1a06..c0fbddfeb 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackMode.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackMode.kt @@ -6,7 +6,7 @@ package org.oxycblt.auxio.playback // IN_ARTIST -> Play from the songs of the artist // IN_ALBUM -> Play from the songs of the album enum class PlaybackMode { - IN_GENRE, IN_ARTIST, IN_ALBUM, ALL_SONGS; + IN_ARTIST, IN_ALBUM, ALL_SONGS; // Make a slice of all the values that this ShowMode covers. // ex. SHOW_ARTISTS would return SHOW_ARTISTS, SHOW_ALBUMS, and SHOW_SONGS diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt index 46982395a..d5e2d8ca2 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt @@ -7,6 +7,7 @@ import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist +import org.oxycblt.auxio.music.BaseModel import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.music.Song @@ -21,8 +22,8 @@ class PlaybackViewModel : ViewModel() { private val mCurrentSong = MutableLiveData() val currentSong: LiveData get() = mCurrentSong - private val mCurrentGenre = MutableLiveData() - val currentGenre: LiveData get() = mCurrentGenre + private val mCurrentParent = MutableLiveData() + val currentParent: LiveData get() = mCurrentParent private val mQueue = MutableLiveData(mutableListOf()) val queue: LiveData> get() = mQueue @@ -62,19 +63,6 @@ class PlaybackViewModel : ViewModel() { PlaybackMode.ALL_SONGS -> musicStore.songs.toMutableList() PlaybackMode.IN_ARTIST -> song.album.artist.songs PlaybackMode.IN_ALBUM -> song.album.songs - - // Warning: Calling update() with a mode of IN_GENRE Will cause Auxio to play - // from the artist's most prominent genre instead of the song's genre. - // FIXME: This could be fixed by moving genre loading to songs - PlaybackMode.IN_GENRE -> { - Log.d( - this::class.simpleName, - "update() was called with IN_GENRES, using " + - "most prominent genre instead of the song's genre." - ) - - song.album.artist.genres[0].songs - } } mCurrentMode.value = mode @@ -90,6 +78,7 @@ class PlaybackViewModel : ViewModel() { mQueue.value = songs mCurrentIndex.value = 0 + mCurrentParent.value = album mCurrentMode.value = PlaybackMode.IN_ALBUM } @@ -102,6 +91,7 @@ class PlaybackViewModel : ViewModel() { mQueue.value = songs mCurrentIndex.value = 0 + mCurrentParent.value = artist mCurrentMode.value = PlaybackMode.IN_ARTIST } @@ -112,10 +102,8 @@ class PlaybackViewModel : ViewModel() { updatePlayback(songs[0]) - mCurrentGenre.value = genre mQueue.value = songs mCurrentIndex.value = 0 - mCurrentMode.value = PlaybackMode.IN_GENRE } private fun updatePlayback(song: Song) { diff --git a/app/src/main/res/layout/fragment_album_detail.xml b/app/src/main/res/layout/fragment_album_detail.xml index b20820f17..ea87a23b4 100644 --- a/app/src/main/res/layout/fragment_album_detail.xml +++ b/app/src/main/res/layout/fragment_album_detail.xml @@ -161,6 +161,7 @@ android:overScrollMode="never" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/album_song_header" tools:itemCount="4" tools:listitem="@layout/item_album_song" /> diff --git a/app/src/main/res/layout/fragment_artist_detail.xml b/app/src/main/res/layout/fragment_artist_detail.xml index f07559831..350863ad4 100644 --- a/app/src/main/res/layout/fragment_artist_detail.xml +++ b/app/src/main/res/layout/fragment_artist_detail.xml @@ -158,6 +158,7 @@ android:overScrollMode="never" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/artist_album_header" tools:itemCount="4" tools:listitem="@layout/item_album" /> diff --git a/app/src/main/res/layout/fragment_genre_detail.xml b/app/src/main/res/layout/fragment_genre_detail.xml index 4b0bc7fa5..51b79c3d2 100644 --- a/app/src/main/res/layout/fragment_genre_detail.xml +++ b/app/src/main/res/layout/fragment_genre_detail.xml @@ -99,23 +99,6 @@ app:layout_constraintTop_toBottomOf="@+id/genre_counts" tools:text="80 Songs" /> - - diff --git a/app/src/main/res/layout/fragment_playback.xml b/app/src/main/res/layout/fragment_playback.xml index c1663bfa2..76f8599f2 100644 --- a/app/src/main/res/layout/fragment_playback.xml +++ b/app/src/main/res/layout/fragment_playback.xml @@ -41,7 +41,6 @@ android:layout_width="0dp" android:layout_height="0dp" android:layout_margin="@dimen/margin_mid_large" - android:elevation="4dp" android:contentDescription="@{@string/description_album_cover(song.name)}" app:coverArt="@{song}" app:layout_constraintBottom_toTopOf="@+id/playback_song"