Improve genre loading
Temporarily remove the ability to play from a genre, update MusicLoader to not load genres/artists simultaniously so that Artist ID's arent completely garbled. Improve PlaybackFragment slightly.
This commit is contained in:
parent
c17666752b
commit
339100e436
12 changed files with 81 additions and 154 deletions
|
@ -121,13 +121,13 @@ class AlbumDetailFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the play button depending on the current playback status
|
// 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
|
// If playing this album -> Make button show media controls
|
||||||
// status, and then set its behavior to modify isPlaying.
|
// If not playing this album -> Make button update playback to the artist
|
||||||
// If the shown album isn't currently playing, set the button to Play and its behavior
|
|
||||||
// to start the playback of the album.
|
|
||||||
private fun updatePlayButton(mode: PlaybackMode, binding: FragmentAlbumDetailBinding) {
|
private fun updatePlayButton(mode: PlaybackMode, binding: FragmentAlbumDetailBinding) {
|
||||||
playbackModel.currentSong.value?.let { song ->
|
playbackModel.currentParent.value?.let { parent ->
|
||||||
if (mode == PlaybackMode.IN_ALBUM && song.album == detailModel.currentAlbum.value) {
|
if (mode == PlaybackMode.IN_ALBUM &&
|
||||||
|
parent.id == detailModel.currentAlbum.value!!.id
|
||||||
|
) {
|
||||||
if (playbackModel.isPlaying.value!!) {
|
if (playbackModel.isPlaying.value!!) {
|
||||||
binding.albumPlay.setImageResource(R.drawable.ic_pause)
|
binding.albumPlay.setImageResource(R.drawable.ic_pause)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -106,14 +106,12 @@ class ArtistDetailFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the play button depending on the current playback status
|
// 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
|
// If playing this artist -> Make button show media controls
|
||||||
// status, and then set its behavior to modify isPlaying.
|
// If not playing this artist -> Make button update playback to the artist
|
||||||
// If the shown artist isn't currently playing, set the button to Play and its behavior
|
|
||||||
// to start the playback of the artist.
|
|
||||||
private fun updatePlayButton(mode: PlaybackMode, binding: FragmentArtistDetailBinding) {
|
private fun updatePlayButton(mode: PlaybackMode, binding: FragmentArtistDetailBinding) {
|
||||||
playbackModel.currentSong.value?.let { song ->
|
playbackModel.currentParent.value?.let { parent ->
|
||||||
if (mode == PlaybackMode.IN_ARTIST &&
|
if (mode == PlaybackMode.IN_ARTIST &&
|
||||||
song.album.artist == detailModel.currentArtist.value
|
parent.id == detailModel.currentArtist.value!!.id
|
||||||
) {
|
) {
|
||||||
if (playbackModel.isPlaying.value!!) {
|
if (playbackModel.isPlaying.value!!) {
|
||||||
binding.artistPlay.setImageResource(R.drawable.ic_pause)
|
binding.artistPlay.setImageResource(R.drawable.ic_pause)
|
||||||
|
|
|
@ -9,12 +9,9 @@ import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import org.oxycblt.auxio.R
|
|
||||||
import org.oxycblt.auxio.databinding.FragmentGenreDetailBinding
|
import org.oxycblt.auxio.databinding.FragmentGenreDetailBinding
|
||||||
import org.oxycblt.auxio.detail.adapters.DetailArtistAdapter
|
import org.oxycblt.auxio.detail.adapters.DetailArtistAdapter
|
||||||
import org.oxycblt.auxio.music.MusicStore
|
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.applyDivider
|
||||||
import org.oxycblt.auxio.theme.disable
|
import org.oxycblt.auxio.theme.disable
|
||||||
|
|
||||||
|
@ -22,7 +19,6 @@ class GenreDetailFragment : Fragment() {
|
||||||
|
|
||||||
private val args: GenreDetailFragmentArgs by navArgs()
|
private val args: GenreDetailFragmentArgs by navArgs()
|
||||||
private val detailModel: DetailViewModel by activityViewModels()
|
private val detailModel: DetailViewModel by activityViewModels()
|
||||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
|
@ -57,7 +53,6 @@ class GenreDetailFragment : Fragment() {
|
||||||
|
|
||||||
binding.lifecycleOwner = this
|
binding.lifecycleOwner = this
|
||||||
binding.detailModel = detailModel
|
binding.detailModel = detailModel
|
||||||
binding.playbackModel = playbackModel
|
|
||||||
binding.genre = detailModel.currentGenre.value
|
binding.genre = detailModel.currentGenre.value
|
||||||
|
|
||||||
binding.genreToolbar.setNavigationOnClickListener {
|
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.")
|
Log.d(this::class.simpleName, "Fragment created.")
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
|
@ -107,27 +94,4 @@ class GenreDetailFragment : Fragment() {
|
||||||
|
|
||||||
detailModel.updateNavigationStatus(false)
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ data class Song(
|
||||||
data class Album(
|
data class Album(
|
||||||
override val id: Long = -1,
|
override val id: Long = -1,
|
||||||
override val name: String,
|
override val name: String,
|
||||||
val artistName: String,
|
val artistId: Long = -1,
|
||||||
val coverUri: Uri = Uri.EMPTY,
|
val coverUri: Uri = Uri.EMPTY,
|
||||||
val year: Int = 0
|
val year: Int = 0
|
||||||
) : BaseModel() {
|
) : BaseModel() {
|
||||||
|
@ -52,8 +52,7 @@ data class Album(
|
||||||
// Artist
|
// Artist
|
||||||
data class Artist(
|
data class Artist(
|
||||||
override val id: Long = -1,
|
override val id: Long = -1,
|
||||||
override var name: String,
|
override var name: String
|
||||||
val givenGenres: MutableList<Genre> = mutableListOf()
|
|
||||||
) : BaseModel() {
|
) : BaseModel() {
|
||||||
val albums = mutableListOf<Album>()
|
val albums = mutableListOf<Album>()
|
||||||
val genres = mutableListOf<Genre>()
|
val genres = mutableListOf<Genre>()
|
||||||
|
@ -75,14 +74,6 @@ data class Artist(
|
||||||
}
|
}
|
||||||
return songs
|
return songs
|
||||||
}
|
}
|
||||||
val genreSongs: MutableList<Song>
|
|
||||||
get() {
|
|
||||||
val songs = mutableListOf<Song>()
|
|
||||||
genres.forEach {
|
|
||||||
songs.addAll(it.songs)
|
|
||||||
}
|
|
||||||
return songs
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Genre
|
// Genre
|
||||||
|
@ -109,14 +100,6 @@ data class Genre(
|
||||||
}
|
}
|
||||||
return num
|
return num
|
||||||
}
|
}
|
||||||
val songs: MutableList<Song>
|
|
||||||
get() {
|
|
||||||
val songs = mutableListOf<Song>()
|
|
||||||
artists.forEach {
|
|
||||||
songs.addAll(it.songs)
|
|
||||||
}
|
|
||||||
return songs
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Header [Used for search, nothing else]
|
// Header [Used for search, nothing else]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package org.oxycblt.auxio.music.processing
|
package org.oxycblt.auxio.music.processing
|
||||||
|
|
||||||
import android.content.ContentResolver
|
import android.content.ContentResolver
|
||||||
import android.database.Cursor
|
import android.provider.MediaStore
|
||||||
import android.provider.MediaStore.Audio.Albums
|
import android.provider.MediaStore.Audio.Albums
|
||||||
import android.provider.MediaStore.Audio.Artists
|
import android.provider.MediaStore.Audio.Artists
|
||||||
import android.provider.MediaStore.Audio.Genres
|
import android.provider.MediaStore.Audio.Genres
|
||||||
|
@ -32,11 +32,6 @@ class MusicLoader(
|
||||||
var albums = mutableListOf<Album>()
|
var albums = mutableListOf<Album>()
|
||||||
var songs = mutableListOf<Song>()
|
var songs = mutableListOf<Song>()
|
||||||
|
|
||||||
private var genreCursor: Cursor? = null
|
|
||||||
private var artistCursor: Cursor? = null
|
|
||||||
private var albumCursor: Cursor? = null
|
|
||||||
private var songCursor: Cursor? = null
|
|
||||||
|
|
||||||
val response: MusicLoaderResponse
|
val response: MusicLoaderResponse
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -67,7 +62,7 @@ class MusicLoader(
|
||||||
Log.d(this::class.simpleName, "Starting genre search...")
|
Log.d(this::class.simpleName, "Starting genre search...")
|
||||||
|
|
||||||
// First, get a cursor for every genre in the android system
|
// First, get a cursor for every genre in the android system
|
||||||
genreCursor = resolver.query(
|
val genreCursor = resolver.query(
|
||||||
Genres.EXTERNAL_CONTENT_URI,
|
Genres.EXTERNAL_CONTENT_URI,
|
||||||
arrayOf(
|
arrayOf(
|
||||||
Genres._ID, // 0
|
Genres._ID, // 0
|
||||||
|
@ -86,7 +81,7 @@ class MusicLoader(
|
||||||
val id = cursor.getLong(idIndex)
|
val id = cursor.getLong(idIndex)
|
||||||
var name = cursor.getString(nameIndex) ?: genrePlaceholder
|
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.
|
// convert that to the corresponding ID3 genre.
|
||||||
if (name.contains(Regex("[0123456789)]"))) {
|
if (name.contains(Regex("[0123456789)]"))) {
|
||||||
name = name.toNamedGenre() ?: genrePlaceholder
|
name = name.toNamedGenre() ?: genrePlaceholder
|
||||||
|
@ -111,42 +106,59 @@ class MusicLoader(
|
||||||
private fun loadArtists() {
|
private fun loadArtists() {
|
||||||
Log.d(this::class.simpleName, "Starting artist search...")
|
Log.d(this::class.simpleName, "Starting artist search...")
|
||||||
|
|
||||||
// Iterate through the artists for each loaded genre, and then add the genre
|
// Load all the artists
|
||||||
// with the artist.
|
val artistCursor = resolver.query(
|
||||||
// This is only done because using GENRE_NAME for songs is broken and has been for years.
|
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) {
|
for (genre in genres) {
|
||||||
artistCursor = resolver.query(
|
val artistGenreCursor = resolver.query(
|
||||||
Genres.Members.getContentUri("external", genre.id),
|
Genres.Members.getContentUri("external", genre.id),
|
||||||
arrayOf(
|
arrayOf(
|
||||||
Artists._ID, // 0
|
Genres.Members.ARTIST_ID
|
||||||
Artists.ARTIST // 1
|
|
||||||
),
|
),
|
||||||
null, null,
|
null, null, null
|
||||||
Artists.DEFAULT_SORT_ORDER
|
|
||||||
)
|
)
|
||||||
|
|
||||||
artistCursor?.use { cursor ->
|
artistGenreCursor?.let { cursor ->
|
||||||
val idIndex = cursor.getColumnIndexOrThrow(Artists._ID)
|
val idIndex = cursor.getColumnIndexOrThrow(Genres.Members.ARTIST_ID)
|
||||||
val nameIndex = cursor.getColumnIndexOrThrow(Artists.ARTIST)
|
|
||||||
|
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
val id = cursor.getLong(idIndex)
|
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
|
artists.filter { it.id == id }.forEach {
|
||||||
// are processed], add the genre to the existing artist instead of creating a
|
it.genres.add(genre)
|
||||||
// new one.
|
|
||||||
val existingArtist = artists.find { it.name == name }
|
|
||||||
|
|
||||||
if (existingArtist != null) {
|
|
||||||
existingArtist.givenGenres.add(genre)
|
|
||||||
} else {
|
|
||||||
artists.add(
|
|
||||||
Artist(
|
|
||||||
id, name,
|
|
||||||
mutableListOf(genre)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,9 +166,8 @@ class MusicLoader(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove dupes [Just in case]
|
|
||||||
artists = artists.distinctBy {
|
artists = artists.distinctBy {
|
||||||
it.name to it.givenGenres
|
it.name to it.genres
|
||||||
}.toMutableList()
|
}.toMutableList()
|
||||||
|
|
||||||
Log.d(
|
Log.d(
|
||||||
|
@ -168,12 +179,12 @@ class MusicLoader(
|
||||||
private fun loadAlbums() {
|
private fun loadAlbums() {
|
||||||
Log.d(this::class.simpleName, "Starting album search...")
|
Log.d(this::class.simpleName, "Starting album search...")
|
||||||
|
|
||||||
albumCursor = resolver.query(
|
val albumCursor = resolver.query(
|
||||||
Albums.EXTERNAL_CONTENT_URI,
|
Albums.EXTERNAL_CONTENT_URI,
|
||||||
arrayOf(
|
arrayOf(
|
||||||
Albums._ID, // 0
|
Albums._ID, // 0
|
||||||
Albums.ALBUM, // 1
|
Albums.ALBUM, // 1
|
||||||
Albums.ARTIST, // 2
|
Albums.ARTIST_ID, // 2
|
||||||
|
|
||||||
Albums.FIRST_YEAR, // 3
|
Albums.FIRST_YEAR, // 3
|
||||||
),
|
),
|
||||||
|
@ -184,20 +195,20 @@ class MusicLoader(
|
||||||
albumCursor?.use { cursor ->
|
albumCursor?.use { cursor ->
|
||||||
val idIndex = cursor.getColumnIndexOrThrow(Albums._ID)
|
val idIndex = cursor.getColumnIndexOrThrow(Albums._ID)
|
||||||
val nameIndex = cursor.getColumnIndexOrThrow(Albums.ALBUM)
|
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)
|
val yearIndex = cursor.getColumnIndexOrThrow(Albums.FIRST_YEAR)
|
||||||
|
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
val id = cursor.getLong(idIndex)
|
val id = cursor.getLong(idIndex)
|
||||||
val name = cursor.getString(nameIndex) ?: albumPlaceholder
|
val name = cursor.getString(nameIndex) ?: albumPlaceholder
|
||||||
val artist = cursor.getString(artistIndex) ?: artistPlaceholder
|
val artistId = cursor.getLong(artistIdIndex)
|
||||||
val year = cursor.getInt(yearIndex)
|
val year = cursor.getInt(yearIndex)
|
||||||
|
|
||||||
val coverUri = id.toAlbumArtURI()
|
val coverUri = id.toAlbumArtURI()
|
||||||
|
|
||||||
albums.add(
|
albums.add(
|
||||||
Album(
|
Album(
|
||||||
id, name, artist,
|
id, name, artistId,
|
||||||
coverUri, year
|
coverUri, year
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -206,9 +217,8 @@ class MusicLoader(
|
||||||
cursor.close()
|
cursor.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove dupes
|
|
||||||
albums = albums.distinctBy {
|
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()
|
}.toMutableList()
|
||||||
|
|
||||||
Log.d(
|
Log.d(
|
||||||
|
@ -220,7 +230,7 @@ class MusicLoader(
|
||||||
private fun loadSongs() {
|
private fun loadSongs() {
|
||||||
Log.d(this::class.simpleName, "Starting song search...")
|
Log.d(this::class.simpleName, "Starting song search...")
|
||||||
|
|
||||||
songCursor = resolver.query(
|
val songCursor = resolver.query(
|
||||||
Media.EXTERNAL_CONTENT_URI,
|
Media.EXTERNAL_CONTENT_URI,
|
||||||
arrayOf(
|
arrayOf(
|
||||||
Media._ID, // 0
|
Media._ID, // 0
|
||||||
|
@ -260,7 +270,6 @@ class MusicLoader(
|
||||||
cursor.close()
|
cursor.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove dupes
|
|
||||||
songs = songs.distinctBy {
|
songs = songs.distinctBy {
|
||||||
it.name to it.albumId to it.track to it.duration
|
it.name to it.albumId to it.track to it.duration
|
||||||
}.toMutableList()
|
}.toMutableList()
|
||||||
|
|
|
@ -51,8 +51,7 @@ class MusicSorter(
|
||||||
if (unknownSongs.size > 0) {
|
if (unknownSongs.size > 0) {
|
||||||
|
|
||||||
val unknownAlbum = Album(
|
val unknownAlbum = Album(
|
||||||
name = albumPlaceholder,
|
name = albumPlaceholder
|
||||||
artistName = artistPlaceholder
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for (song in unknownSongs) {
|
for (song in unknownSongs) {
|
||||||
|
@ -76,7 +75,7 @@ class MusicSorter(
|
||||||
|
|
||||||
for (artist in artists) {
|
for (artist in artists) {
|
||||||
// Find all albums that match the current artist name
|
// 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
|
// Then add them to the artist, along with refreshing the amount of albums
|
||||||
for (album in artistAlbums) {
|
for (album in artistAlbums) {
|
||||||
|
@ -85,8 +84,9 @@ class MusicSorter(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then group the artist's genres and sort them by "Prominence"
|
// Then group the artist's genres and sort them by "Prominence"
|
||||||
// A.K.A Who has the most map entries
|
// A.K.A Who has the most bugged duplicate genres
|
||||||
val groupedGenres = artist.givenGenres.groupBy { it.name }
|
val groupedGenres = artist.genres.groupBy { it.name }
|
||||||
|
artist.genres.clear()
|
||||||
|
|
||||||
groupedGenres.keys.sortedByDescending { key ->
|
groupedGenres.keys.sortedByDescending { key ->
|
||||||
groupedGenres[key]?.size
|
groupedGenres[key]?.size
|
||||||
|
@ -129,7 +129,7 @@ class MusicSorter(
|
||||||
for (genre in genres) {
|
for (genre in genres) {
|
||||||
// Find all artists that match the current genre
|
// Find all artists that match the current genre
|
||||||
val genreArtists = artists.filter { artist ->
|
val genreArtists = artists.filter { artist ->
|
||||||
artist.givenGenres.any {
|
artist.genres.any {
|
||||||
it.name == genre.name
|
it.name == genre.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ package org.oxycblt.auxio.playback
|
||||||
// IN_ARTIST -> Play from the songs of the artist
|
// IN_ARTIST -> Play from the songs of the artist
|
||||||
// IN_ALBUM -> Play from the songs of the album
|
// IN_ALBUM -> Play from the songs of the album
|
||||||
enum class PlaybackMode {
|
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.
|
// Make a slice of all the values that this ShowMode covers.
|
||||||
// ex. SHOW_ARTISTS would return SHOW_ARTISTS, SHOW_ALBUMS, and SHOW_SONGS
|
// ex. SHOW_ARTISTS would return SHOW_ARTISTS, SHOW_ALBUMS, and SHOW_SONGS
|
||||||
|
|
|
@ -7,6 +7,7 @@ import androidx.lifecycle.Transformations
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
|
import org.oxycblt.auxio.music.BaseModel
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
import org.oxycblt.auxio.music.MusicStore
|
import org.oxycblt.auxio.music.MusicStore
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
|
@ -21,8 +22,8 @@ class PlaybackViewModel : ViewModel() {
|
||||||
private val mCurrentSong = MutableLiveData<Song>()
|
private val mCurrentSong = MutableLiveData<Song>()
|
||||||
val currentSong: LiveData<Song> get() = mCurrentSong
|
val currentSong: LiveData<Song> get() = mCurrentSong
|
||||||
|
|
||||||
private val mCurrentGenre = MutableLiveData<Genre>()
|
private val mCurrentParent = MutableLiveData<BaseModel>()
|
||||||
val currentGenre: LiveData<Genre> get() = mCurrentGenre
|
val currentParent: LiveData<BaseModel> get() = mCurrentParent
|
||||||
|
|
||||||
private val mQueue = MutableLiveData(mutableListOf<Song>())
|
private val mQueue = MutableLiveData(mutableListOf<Song>())
|
||||||
val queue: LiveData<MutableList<Song>> get() = mQueue
|
val queue: LiveData<MutableList<Song>> get() = mQueue
|
||||||
|
@ -62,19 +63,6 @@ class PlaybackViewModel : ViewModel() {
|
||||||
PlaybackMode.ALL_SONGS -> musicStore.songs.toMutableList()
|
PlaybackMode.ALL_SONGS -> musicStore.songs.toMutableList()
|
||||||
PlaybackMode.IN_ARTIST -> song.album.artist.songs
|
PlaybackMode.IN_ARTIST -> song.album.artist.songs
|
||||||
PlaybackMode.IN_ALBUM -> song.album.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
|
mCurrentMode.value = mode
|
||||||
|
@ -90,6 +78,7 @@ class PlaybackViewModel : ViewModel() {
|
||||||
|
|
||||||
mQueue.value = songs
|
mQueue.value = songs
|
||||||
mCurrentIndex.value = 0
|
mCurrentIndex.value = 0
|
||||||
|
mCurrentParent.value = album
|
||||||
mCurrentMode.value = PlaybackMode.IN_ALBUM
|
mCurrentMode.value = PlaybackMode.IN_ALBUM
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,6 +91,7 @@ class PlaybackViewModel : ViewModel() {
|
||||||
|
|
||||||
mQueue.value = songs
|
mQueue.value = songs
|
||||||
mCurrentIndex.value = 0
|
mCurrentIndex.value = 0
|
||||||
|
mCurrentParent.value = artist
|
||||||
mCurrentMode.value = PlaybackMode.IN_ARTIST
|
mCurrentMode.value = PlaybackMode.IN_ARTIST
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,10 +102,8 @@ class PlaybackViewModel : ViewModel() {
|
||||||
|
|
||||||
updatePlayback(songs[0])
|
updatePlayback(songs[0])
|
||||||
|
|
||||||
mCurrentGenre.value = genre
|
|
||||||
mQueue.value = songs
|
mQueue.value = songs
|
||||||
mCurrentIndex.value = 0
|
mCurrentIndex.value = 0
|
||||||
mCurrentMode.value = PlaybackMode.IN_GENRE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updatePlayback(song: Song) {
|
private fun updatePlayback(song: Song) {
|
||||||
|
|
|
@ -161,6 +161,7 @@
|
||||||
android:overScrollMode="never"
|
android:overScrollMode="never"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/album_song_header"
|
app:layout_constraintTop_toBottomOf="@+id/album_song_header"
|
||||||
tools:itemCount="4"
|
tools:itemCount="4"
|
||||||
tools:listitem="@layout/item_album_song" />
|
tools:listitem="@layout/item_album_song" />
|
||||||
|
|
|
@ -158,6 +158,7 @@
|
||||||
android:overScrollMode="never"
|
android:overScrollMode="never"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/artist_album_header"
|
app:layout_constraintTop_toBottomOf="@+id/artist_album_header"
|
||||||
tools:itemCount="4"
|
tools:itemCount="4"
|
||||||
tools:listitem="@layout/item_album" />
|
tools:listitem="@layout/item_album" />
|
||||||
|
|
|
@ -99,23 +99,6 @@
|
||||||
app:layout_constraintTop_toBottomOf="@+id/genre_counts"
|
app:layout_constraintTop_toBottomOf="@+id/genre_counts"
|
||||||
tools:text="80 Songs" />
|
tools:text="80 Songs" />
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/genre_play"
|
|
||||||
style="@style/Widget.AppCompat.Button.Borderless"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_marginTop="@dimen/margin_tiny"
|
|
||||||
android:layout_marginEnd="@dimen/margin_medium"
|
|
||||||
android:background="@drawable/ui_circular_button"
|
|
||||||
android:backgroundTint="?android:attr/colorPrimary"
|
|
||||||
android:contentDescription="@string/description_play"
|
|
||||||
android:src="@drawable/ic_play"
|
|
||||||
android:onClick="@{() -> playbackModel.play(genre, false)}"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/genre_song_count"
|
|
||||||
app:layout_constraintDimensionRatio="1:1"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/genre_counts" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/genre_artist_header"
|
android:id="@+id/genre_artist_header"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -159,6 +142,7 @@
|
||||||
android:overScrollMode="never"
|
android:overScrollMode="never"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/genre_artist_header"
|
app:layout_constraintTop_toBottomOf="@+id/genre_artist_header"
|
||||||
tools:itemCount="4"
|
tools:itemCount="4"
|
||||||
tools:listitem="@layout/item_artist" />
|
tools:listitem="@layout/item_artist" />
|
||||||
|
|
|
@ -41,7 +41,6 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_margin="@dimen/margin_mid_large"
|
android:layout_margin="@dimen/margin_mid_large"
|
||||||
android:elevation="4dp"
|
|
||||||
android:contentDescription="@{@string/description_album_cover(song.name)}"
|
android:contentDescription="@{@string/description_album_cover(song.name)}"
|
||||||
app:coverArt="@{song}"
|
app:coverArt="@{song}"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/playback_song"
|
app:layout_constraintBottom_toTopOf="@+id/playback_song"
|
||||||
|
|
Loading…
Reference in a new issue