Add Genre sorting & better placeholders

* Add Genre sorting to MusicSorter.

* Revamp placeholders so that theyre assigned when loading instead of using a BindingAdapter.
This commit is contained in:
OxygenCobalt 2020-08-31 16:10:32 -06:00
parent d158fc5786
commit 736e335ccf
11 changed files with 82 additions and 66 deletions

View file

@ -2,8 +2,10 @@ package org.oxycblt.auxio.music
import android.app.Application
import android.util.Log
import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.models.Album
import org.oxycblt.auxio.music.models.Artist
import org.oxycblt.auxio.music.models.Genre
import org.oxycblt.auxio.music.models.Song
import org.oxycblt.auxio.music.processing.MusicLoader
import org.oxycblt.auxio.music.processing.MusicLoaderResponse
@ -12,6 +14,7 @@ import org.oxycblt.auxio.music.processing.MusicSorter
// Storage for music data.
class MusicRepository {
lateinit var genres: List<Genre>
lateinit var artists: List<Artist>
lateinit var albums: List<Album>
lateinit var songs: List<Song>
@ -26,14 +29,20 @@ class MusicRepository {
if (loader.response == MusicLoaderResponse.DONE) {
// If the loading succeeds, then process the songs and set them.
val sorter = MusicSorter(
loader.genres,
loader.artists,
loader.albums,
loader.songs
loader.songs,
app.applicationContext.getString(R.string.label_unknown_genre),
app.applicationContext.getString(R.string.label_unknown_artist),
app.applicationContext.getString(R.string.label_unknown_album)
)
songs = sorter.songs.toList()
albums = sorter.albums.toList()
artists = sorter.artists.toList()
genres = sorter.genres.toList()
val elapsed = System.currentTimeMillis() - start

View file

@ -92,19 +92,3 @@ fun TextView.getAlbumSongs(album: Album) {
context.getString(R.string.format_multi_song_count, album.numSongs.toString())
}
}
@BindingAdapter("songInfo")
fun TextView.getSongInfo(song: Song) {
var artist = song.album.artist.name
var album = song.album.title
if (artist == "") {
artist = context.getString(R.string.label_unknown_artist)
}
if (album == "") {
album = context.getString(R.string.label_unknown_album)
}
text = context.getString(R.string.format_song_info, artist, album)
}

View file

@ -5,8 +5,8 @@ import android.net.Uri
// Abstraction for Song
data class Album(
val id: Long = 0L,
val title: String = "",
val artistName: String = "",
var title: String = "",
val artistName: String = "", // Only used for sorting. Use artist for everything else.
val coverUri: Uri = Uri.EMPTY,
val year: Int = 0,
var numSongs: Int = 0

View file

@ -3,8 +3,8 @@ package org.oxycblt.auxio.music.models
// Abstraction for mAlbums
data class Artist(
val id: Long = 0,
val name: String = "",
val genres: MutableList<String> = mutableListOf("")
var name: String = "",
val genres: MutableList<Genre> = mutableListOf(Genre())
) {
val albums = mutableListOf<Album>()
var numAlbums = 0

View file

@ -1,6 +1,9 @@
package org.oxycblt.auxio.music.models
data class Genre(
val id: Long,
val name: String
)
val id: Long = 0,
var name: String = "",
) {
val artists = mutableListOf<Artist>()
var numArtists = 0
}

View file

@ -5,8 +5,8 @@ import android.text.format.DateUtils
// Class containing all relevant values for a song.
data class Song(
val id: Long,
val title: String,
val albumName: String,
var title: String,
val albumName: String, // Only used for sorting. Use artist for everything else.
val track: Int,
val duration: Long
) {

View file

@ -130,12 +130,12 @@ class MusicLoader(private val resolver: ContentResolver) {
val existingArtist = artists.find { it.name == name }
if (existingArtist != null) {
existingArtist.genres.add(genre.name)
existingArtist.genres.add(genre)
} else {
artists.add(
Artist(
id, name,
mutableListOf(genre.name)
mutableListOf(genre)
)
)
}

View file

@ -3,16 +3,25 @@ package org.oxycblt.auxio.music.processing
import android.util.Log
import org.oxycblt.auxio.music.models.Album
import org.oxycblt.auxio.music.models.Artist
import org.oxycblt.auxio.music.models.Genre
import org.oxycblt.auxio.music.models.Song
class MusicSorter(
val genres: MutableList<Genre>,
val artists: MutableList<Artist>,
val albums: MutableList<Album>,
val songs: MutableList<Song>
val songs: MutableList<Song>,
private val genrePlaceholder: String,
private val artistPlaceholder: String,
private val albumPlaceholder: String,
) {
init {
sortSongsIntoAlbums()
sortAlbumsIntoArtists()
sortArtistsIntoGenres()
addPlaceholders()
}
private fun sortSongsIntoAlbums() {
@ -88,10 +97,57 @@ class MusicSorter(
unknownArtist.numAlbums = albums.size
artists.add(unknownArtist)
Log.d(
this::class.simpleName,
"${unknownAlbums.size} albums were placed into an unknown artist."
)
}
}
private fun sortArtistsIntoGenres() {
Log.d(this::class.simpleName, "Sorting artists into genres...")
val unknownArtists = artists.toMutableList()
for (genre in genres) {
// Find all artists that match the current genre
val genreArtists = artists.filter { artist ->
artist.genres.any {
it.name == genre.name
}
}
// Then add them to the genre, along with refreshing the amount of artists
genre.artists.addAll(genreArtists)
genre.numArtists = artists.size
unknownArtists.removeAll(genreArtists)
}
if (unknownArtists.size > 0) {
// Reuse an existing unknown genre if one is found
val unknownGenre = genres.find { it.name == "" } ?: Genre()
for (artist in unknownArtists) {
artist.genres.add(unknownGenre)
unknownGenre.artists.add(artist)
}
unknownGenre.numArtists = artists.size
Log.d(
this::class.simpleName,
"${unknownArtists.size} albums were placed into an unknown genre."
)
}
}
// Correct any empty names [""] with the proper placeholders [Unknown Album]
private fun addPlaceholders() {
genres.forEach { if (it.name == "") it.name = genrePlaceholder }
artists.forEach { if (it.name == "") it.name = artistPlaceholder }
albums.forEach { if (it.title == "") it.title = albumPlaceholder }
}
}

View file

@ -11,14 +11,7 @@ class AlbumAdapter(private val data: List<Album>) : RecyclerView.Adapter<AlbumVi
override fun getItemCount(): Int = data.size
/*
private var time = 0
private var inflationCount = 0
*/
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AlbumViewHolder {
// val then = System.currentTimeMillis()
val binding = AlbumItemBinding.inflate(LayoutInflater.from(parent.context))
// Force the item to *actually* be the screen width so ellipsizing can work.
@ -26,18 +19,6 @@ class AlbumAdapter(private val data: List<Album>) : RecyclerView.Adapter<AlbumVi
RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT
)
/*
time += (System.currentTimeMillis() - then).toInt()
inflationCount++
if (inflationCount == 10) {
Log.d(
this::class.simpleName,
"Initial inflation took ${time}ms"
)
}
*/
return AlbumViewHolder(binding)
}

View file

@ -11,11 +11,6 @@ class SongAdapter(private val data: List<Song>) : RecyclerView.Adapter<SongViewH
override fun getItemCount(): Int = data.size
/*
private var time = 0
private var inflationCount = 0
*/
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongViewHolder {
val then = System.currentTimeMillis()
@ -26,18 +21,6 @@ class SongAdapter(private val data: List<Song>) : RecyclerView.Adapter<SongViewH
RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT
)
/*
time += (System.currentTimeMillis() - then).toInt()
inflationCount++
if (inflationCount == 10) {
Log.d(
this::class.simpleName,
"Initial inflation took ${time}ms"
)
}
*/
return SongViewHolder(binding)
}

View file

@ -52,7 +52,7 @@
android:maxLines="1"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
app:songInfo="@{song}"
android:text="@{@string/format_song_info(song.album.artist.name, song.album.title)}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/duration"
app:layout_constraintStart_toEndOf="@+id/cover"