From 016d664e51006abb954dc9b76966491d3ed15d35 Mon Sep 17 00:00:00 2001 From: OxygenCobalt Date: Sun, 6 Sep 2020 18:51:01 -0600 Subject: [PATCH] Update Music Loading Slightly tweak the music models, use plural strings when formatting args, and properly sort the music items after everything else is sorted. --- .gitignore | 1 + app/proguard-rules.pro | 4 +- .../java/org/oxycblt/auxio/MainActivity.kt | 2 + .../oxycblt/auxio/loading/LoadingFragment.kt | 2 - .../org/oxycblt/auxio/music/MusicUtils.kt | 54 +++++++------------ .../org/oxycblt/auxio/music/models/Album.kt | 8 +-- .../org/oxycblt/auxio/music/models/Artist.kt | 4 +- .../org/oxycblt/auxio/music/models/Genre.kt | 2 - .../org/oxycblt/auxio/music/models/Song.kt | 4 +- .../auxio/music/processing/MusicLoader.kt | 13 ++--- .../auxio/music/processing/MusicSorter.kt | 25 ++++----- .../org/oxycblt/auxio/songs/SongsFragment.kt | 2 +- app/src/main/res/layout/album_item.xml | 2 +- app/src/main/res/layout/artist_item.xml | 2 +- app/src/main/res/layout/song_item.xml | 4 +- app/src/main/res/values/strings.xml | 18 ++++--- 16 files changed, 68 insertions(+), 79 deletions(-) diff --git a/.gitignore b/.gitignore index 226f2e82f..0e09184a7 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .gradle local.properties build/ +release/ # Studio .idea/ diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 481bb4348..f5fb65b3f 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -18,4 +18,6 @@ # If you keep the line number information, uncomment this to # hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file +#-renamesourcefileattribute SourceFile + +-dontobfuscate \ No newline at end of file diff --git a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt index e9b54d820..f0c15ea56 100644 --- a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt +++ b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt @@ -11,6 +11,8 @@ import org.oxycblt.auxio.theme.accent class MainActivity : AppCompatActivity() { + // TODO: Collapse LoadingFragment/MainFragment into MainActivity. + override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? { // Debugging placeholder AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) diff --git a/app/src/main/java/org/oxycblt/auxio/loading/LoadingFragment.kt b/app/src/main/java/org/oxycblt/auxio/loading/LoadingFragment.kt index b0f766f37..fc650e828 100644 --- a/app/src/main/java/org/oxycblt/auxio/loading/LoadingFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/loading/LoadingFragment.kt @@ -21,8 +21,6 @@ import org.oxycblt.auxio.music.processing.MusicLoaderResponse class LoadingFragment : Fragment(R.layout.fragment_loading) { - // TODO: Phase out LoadingFragment - private val loadingModel: LoadingViewModel by lazy { ViewModelProvider( this, 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 07ee8baf8..e98592f9b 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt @@ -3,6 +3,7 @@ package org.oxycblt.auxio.music import android.content.ContentUris import android.net.Uri import android.provider.MediaStore +import android.util.Log import android.widget.ImageView import android.widget.TextView import androidx.databinding.BindingAdapter @@ -65,57 +66,40 @@ fun Long.toAlbumArtURI(): Uri { ) } -fun Int.toSongCount(): Int { - return if (this < 2) { - R.string.label_single_song - } else { - R.string.format_multi_song_count - } -} - -fun Int.toAlbumCount(): Int { - return if (this < 2) { - R.string.label_single_album - } else { - R.string.format_album_count - } -} - // Format the amount of songs in an album @BindingAdapter("songCount") fun TextView.getAlbumSongs(album: Album) { - text = context.getString(album.numSongs.toSongCount(), album.numSongs) + text = context.resources.getQuantityString(R.plurals.format_song_count, album.numSongs) } -@BindingAdapter("albumSongCount") -fun TextView.getSongAlbumCount(artist: Artist) { - val albums = context.getString(artist.numAlbums.toAlbumCount(), artist.numAlbums) - val songs = context.getString(artist.numSongs.toSongCount(), artist.numSongs) +@BindingAdapter("artistCounts") +fun TextView.getArtistCounts(artist: Artist) { + // Get the quantity string for both albums & artists, and then stitch them together. + val albums = context.resources.getQuantityString( + R.plurals.format_albums, artist.numAlbums, artist.numAlbums + ) + val songs = context.resources.getQuantityString( + R.plurals.format_song_count, artist.numSongs, artist.numSongs + ) - text = context.getString(R.string.format_combined_song_album, albums, songs) + Log.d("getArtistCounts", albums) + + text = context.getString(R.string.format_double_counts, albums, songs) } // Get the cover art @BindingAdapter("coverArt") -fun ImageView.getCoverArt(any: Any) { - val uri = when (any) { - is Song -> any.album.coverUri - is Album -> any.coverUri - - else -> Uri.EMPTY - } - - load(uri) { +fun ImageView.getCoverArt(song: Song) { + load(song.album.coverUri) { crossfade(true) placeholder(android.R.color.transparent) error(R.drawable.ic_music) } } -// Get the artist image. -@BindingAdapter("artistImage") -fun ImageView.getArtistImage(artist: Artist) { - load(artist.albums[0].coverUri) { +@BindingAdapter("coverArt") +fun ImageView.getCoverArt(album: Album) { + load(album.coverUri) { crossfade(true) placeholder(android.R.color.transparent) error(R.drawable.ic_music) diff --git a/app/src/main/java/org/oxycblt/auxio/music/models/Album.kt b/app/src/main/java/org/oxycblt/auxio/music/models/Album.kt index 9d5262891..1c215d536 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/models/Album.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/models/Album.kt @@ -5,15 +5,15 @@ import android.net.Uri // Abstraction for Song data class Album( val id: Long = 0L, - var title: String = "", - val artistName: String = "", // Only used for sorting. Use artist for everything else. + var name: String = "", + val artistName: String = "", // only used for sorting. Use artist.name instead. val coverUri: Uri = Uri.EMPTY, - val year: Int = 0, - var numSongs: Int = 0 + val year: Int = 0 ) { lateinit var artist: Artist val songs = mutableListOf() + val numSongs: Int get() = songs.size fun finalize() { songs.sortBy { it.track } diff --git a/app/src/main/java/org/oxycblt/auxio/music/models/Artist.kt b/app/src/main/java/org/oxycblt/auxio/music/models/Artist.kt index 4bbb2b1a2..9c120a239 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/models/Artist.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/models/Artist.kt @@ -7,13 +7,13 @@ data class Artist( val genres: MutableList = mutableListOf(Genre()) ) { val albums = mutableListOf() - var numAlbums = 0 + + val numAlbums: Int get() = albums.size var numSongs = 0 fun finalize() { albums.sortByDescending { it.year } - numAlbums = albums.size albums.forEach { album -> numSongs += album.numSongs } diff --git a/app/src/main/java/org/oxycblt/auxio/music/models/Genre.kt b/app/src/main/java/org/oxycblt/auxio/music/models/Genre.kt index 4840b4fb7..60ca100d2 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/models/Genre.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/models/Genre.kt @@ -5,10 +5,8 @@ data class Genre( var name: String = "", ) { val artists = mutableListOf() - var numArtists = 0 fun finalize() { artists.sortByDescending { it.name } - numArtists = artists.size } } diff --git a/app/src/main/java/org/oxycblt/auxio/music/models/Song.kt b/app/src/main/java/org/oxycblt/auxio/music/models/Song.kt index c0aaa8286..4312098ee 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/models/Song.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/models/Song.kt @@ -5,8 +5,8 @@ import android.text.format.DateUtils // Class containing all relevant values for a song. data class Song( val id: Long, - var title: String, - val albumName: String, // Only used for sorting. Use artist for everything else. + var name: String, + val albumName: String, // Only used for sorting. Use album.title for everything else. val track: Int, val duration: Long ) { 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 c71fbcdfb..2677b88bc 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 @@ -113,8 +113,8 @@ class MusicLoader(private val resolver: ContentResolver) { artistCursor = resolver.query( Genres.Members.getContentUri("external", genre.id), arrayOf( - Artists._ID, - Artists.ARTIST + Artists._ID, // 0 + Artists.ARTIST // 1 ), null, null, Artists.DEFAULT_SORT_ORDER @@ -171,7 +171,6 @@ class MusicLoader(private val resolver: ContentResolver) { Albums.ARTIST, // 2 Albums.FIRST_YEAR, // 3 - Albums.NUMBER_OF_SONGS // 4 ), null, null, Albums.DEFAULT_SORT_ORDER @@ -182,21 +181,19 @@ class MusicLoader(private val resolver: ContentResolver) { val nameIndex = cursor.getColumnIndexOrThrow(Albums.ALBUM) val artistIndex = cursor.getColumnIndexOrThrow(Albums.ARTIST) val yearIndex = cursor.getColumnIndexOrThrow(Albums.FIRST_YEAR) - val numIndex = cursor.getColumnIndexOrThrow(Albums.NUMBER_OF_SONGS) while (cursor.moveToNext()) { val id = cursor.getLong(idIndex) val name = cursor.getString(nameIndex) ?: "" val artist = cursor.getString(artistIndex) ?: "" val year = cursor.getInt(yearIndex) - val numSongs = cursor.getInt(numIndex) val coverUri = id.toAlbumArtURI() albums.add( Album( id, name, artist, - coverUri, year, numSongs + coverUri, year ) ) } @@ -206,7 +203,7 @@ class MusicLoader(private val resolver: ContentResolver) { // Remove dupes albums = albums.distinctBy { - it.title to it.artistName to it.year to it.numSongs + it.name to it.artistName to it.year to it.numSongs }.toMutableList() Log.d( @@ -260,7 +257,7 @@ class MusicLoader(private val resolver: ContentResolver) { // Remove dupes songs = songs.distinctBy { - it.title to it.albumName to it.track to it.duration + it.name to it.albumName to it.track to it.duration }.toMutableList() Log.d( 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 d4fcd1250..66edb1caf 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 @@ -22,6 +22,7 @@ class MusicSorter( sortArtistsIntoGenres() addPlaceholders() + finalizeMusic() } private fun sortSongsIntoAlbums() { @@ -31,7 +32,7 @@ class MusicSorter( for (album in albums) { // Find all songs that match the current album title - val albumSongs = songs.filter { it.albumName == album.title } + val albumSongs = songs.filter { it.albumName == album.name } // Then add them to the album for (song in albumSongs) { @@ -46,14 +47,13 @@ class MusicSorter( if (unknownSongs.size > 0) { // Reuse an existing unknown album if one is found - val unknownAlbum = albums.find { it.title == "" } ?: Album() + val unknownAlbum = albums.find { it.name == "" } ?: Album() for (song in unknownSongs) { song.album = unknownAlbum unknownAlbum.songs.add(song) } - unknownAlbum.numSongs = unknownAlbum.songs.size unknownAlbum.finalize() albums.add(unknownAlbum) @@ -63,8 +63,6 @@ class MusicSorter( "${unknownSongs.size} songs were placed into an unknown album." ) } - - albums.sortByDescending { it.title } } private fun sortAlbumsIntoArtists() { @@ -107,8 +105,6 @@ class MusicSorter( "${unknownAlbums.size} albums were placed into an unknown artist." ) } - - artists.sortByDescending { it.name } } private fun sortArtistsIntoGenres() { @@ -126,7 +122,7 @@ class MusicSorter( // Then add them to the genre, along with refreshing the amount of artists genre.artists.addAll(genreArtists) - genre.numArtists = artists.size + genre.finalize() unknownArtists.removeAll(genreArtists) } @@ -140,7 +136,7 @@ class MusicSorter( unknownGenre.artists.add(artist) } - unknownGenre.numArtists = artists.size + unknownGenre.finalize() genres.add(unknownGenre) @@ -149,14 +145,19 @@ class MusicSorter( "${unknownArtists.size} albums were placed into an unknown genre." ) } - - genres.sortByDescending { it.name } } // 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 } + albums.forEach { if (it.name == "") it.name = albumPlaceholder } + } + + // Sort all music into + private fun finalizeMusic() { + genres.sortBy { it.name } + artists.sortBy { it.name } + albums.sortBy { it.name } } } diff --git a/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt b/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt index 562e1144d..122b67a9f 100644 --- a/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt @@ -32,7 +32,7 @@ class SongsFragment : Fragment() { binding.songRecycler.adapter = SongAdapter( songsModel.songs.value!!, ClickListener { song -> - Log.d(this::class.simpleName, song.title) + Log.d(this::class.simpleName, song.name) } ) binding.songRecycler.applyDivider() diff --git a/app/src/main/res/layout/album_item.xml b/app/src/main/res/layout/album_item.xml index 716f71872..4d9a2035c 100644 --- a/app/src/main/res/layout/album_item.xml +++ b/app/src/main/res/layout/album_item.xml @@ -34,7 +34,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="@dimen/margin_medium" - android:text="@{album.title}" + android:text="@{album.name}" android:textAppearance="?android:attr/textAppearanceListItem" android:textColor="?android:attr/textColorPrimary" android:ellipsize="end" diff --git a/app/src/main/res/layout/artist_item.xml b/app/src/main/res/layout/artist_item.xml index 4fb1e8ff1..7c6a48da4 100644 --- a/app/src/main/res/layout/artist_item.xml +++ b/app/src/main/res/layout/artist_item.xml @@ -42,7 +42,7 @@ android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceListItemSecondary" android:textColor="?android:attr/textColorSecondary" - app:albumSongCount="@{artist}" + app:artistCounts="@{artist}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/artist_name" diff --git a/app/src/main/res/layout/song_item.xml b/app/src/main/res/layout/song_item.xml index 740886715..ede29d877 100644 --- a/app/src/main/res/layout/song_item.xml +++ b/app/src/main/res/layout/song_item.xml @@ -36,7 +36,7 @@ android:layout_marginStart="@dimen/margin_medium" android:ellipsize="end" android:maxLines="1" - android:text="@{song.title}" + android:text="@{song.name}" android:textAppearance="?android:attr/textAppearanceListItem" android:textColor="?android:attr/textColorPrimary" app:layout_constraintBottom_toTopOf="@+id/song_info" @@ -55,7 +55,7 @@ android:maxLines="1" android:textAppearance="?android:attr/textAppearanceListItemSecondary" android:textColor="?android:attr/textColorSecondary" - android:text="@{@string/format_song_info(song.album.artist.name, song.album.title)}" + android:text="@{@string/format_song_info(song.album.artist.name, song.album.name)}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/duration" app:layout_constraintStart_toEndOf="@+id/cover" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 405ef6b5c..7a328f15a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -11,15 +11,21 @@ Retry Grant - 1 Song - 1 Album Unknown Genre Unknown Artist Unknown Album - %s Songs - %s / %s - %s Albums - %s, %s + %1$s / %2$s + %1$s, %2$s + + + %s Song + %s Songs + + + + %s Album + %s Albums + \ No newline at end of file