From a93c0f4af3d1cada80f35042f904cac06735de38 Mon Sep 17 00:00:00 2001 From: OxygenCobalt Date: Mon, 7 Sep 2020 09:34:19 -0600 Subject: [PATCH] Add artist images Add artist images back, now with proper mosaics. --- .../org/oxycblt/auxio/music/MusicUtils.kt | 36 ++++++- .../auxio/music/coil/ArtistImageFetcher.kt | 97 +++++++++++++++++++ .../auxio/music/processing/MusicSorter.kt | 16 ++- app/src/main/res/drawable/ic_album.xml | 11 +++ app/src/main/res/drawable/ic_artist.xml | 11 +++ app/src/main/res/layout/artist_item.xml | 17 +++- 6 files changed, 177 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/org/oxycblt/auxio/music/coil/ArtistImageFetcher.kt create mode 100644 app/src/main/res/drawable/ic_album.xml create mode 100644 app/src/main/res/drawable/ic_artist.xml 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 e98592f9b..06b7a6f08 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt @@ -3,12 +3,14 @@ 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 +import coil.Coil import coil.load +import coil.request.ImageRequest import org.oxycblt.auxio.R +import org.oxycblt.auxio.music.coil.ArtistImageFetcher import org.oxycblt.auxio.music.models.Album import org.oxycblt.auxio.music.models.Artist import org.oxycblt.auxio.music.models.Song @@ -82,8 +84,6 @@ fun TextView.getArtistCounts(artist: Artist) { R.plurals.format_song_count, artist.numSongs, artist.numSongs ) - Log.d("getArtistCounts", albums) - text = context.getString(R.string.format_double_counts, albums, songs) } @@ -102,6 +102,34 @@ fun ImageView.getCoverArt(album: Album) { load(album.coverUri) { crossfade(true) placeholder(android.R.color.transparent) - error(R.drawable.ic_music) + error(R.drawable.ic_album) + } +} + +@BindingAdapter("artistImage") +fun ImageView.getArtistImage(artist: Artist) { + if (artist.numAlbums >= 4) { + val uris = mutableListOf() + + for (i in 0..3) { + uris.add(artist.albums[i].coverUri) + } + + val request = ImageRequest.Builder(context) + .data(uris) + .fetcher(ArtistImageFetcher(context)) + .crossfade(true) + .placeholder(android.R.color.transparent) + .error(R.drawable.ic_artist) + .target(this) + .build() + + Coil.imageLoader(context).enqueue(request) + } else { + load(artist.albums[0].coverUri) { + crossfade(true) + placeholder(android.R.color.transparent) + error(R.drawable.ic_music) + } } } diff --git a/app/src/main/java/org/oxycblt/auxio/music/coil/ArtistImageFetcher.kt b/app/src/main/java/org/oxycblt/auxio/music/coil/ArtistImageFetcher.kt new file mode 100644 index 000000000..6e0750348 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/music/coil/ArtistImageFetcher.kt @@ -0,0 +1,97 @@ +package org.oxycblt.auxio.music.coil + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.net.Uri +import androidx.core.graphics.drawable.toDrawable +import coil.bitmap.BitmapPool +import coil.decode.DataSource +import coil.decode.Options +import coil.fetch.DrawableResult +import coil.fetch.FetchResult +import coil.fetch.Fetcher +import coil.fetch.SourceResult +import coil.size.Size +import okio.buffer +import okio.source +import java.io.InputStream + +const val MOSAIC_BITMAP_SIZE = 512 + +class ArtistImageFetcher(private val context: Context) : Fetcher> { + override suspend fun fetch( + pool: BitmapPool, + data: List, + size: Size, + options: Options + ): FetchResult { + val streams = mutableListOf() + + for (uri in data) { + val stream: InputStream? = context.contentResolver.openInputStream(uri) + + if (stream != null) { + streams.add(stream) + } + } + + // If so many streams failed that there's not enough images to make a mosaic, then + // just return the first album. + if (streams.size < 4) { + streams.forEach { it.close() } + + return SourceResult( + source = streams[0].source().buffer(), + mimeType = context.contentResolver.getType(data[0]), + dataSource = DataSource.DISK + ) + } + + // Create the mosaic, code adapted from Phonograph. + // https://github.com/kabouzeid/Phonograph + val finalBitmap = Bitmap.createBitmap( + MOSAIC_BITMAP_SIZE, MOSAIC_BITMAP_SIZE, Bitmap.Config.RGB_565 + ) + + val canvas = Canvas(finalBitmap) + + var x = 0 + var y = 0 + val increment = MOSAIC_BITMAP_SIZE / 2 + + for (stream in streams) { + val bitmap = Bitmap.createScaledBitmap( + BitmapFactory.decodeStream(stream), + increment, + increment, + true + ) + + canvas.drawBitmap(bitmap, x.toFloat(), y.toFloat(), null) + + x += increment + + if (x == MOSAIC_BITMAP_SIZE) { + x = 0 + y += increment + + if (y == MOSAIC_BITMAP_SIZE) { + break + } + } + } + + // Close all the streams when done. + streams.forEach { it.close() } + + return DrawableResult( + drawable = finalBitmap.toDrawable(context.resources), + isSampled = false, + dataSource = DataSource.DISK + ) + } + + override fun key(data: List): String? = data.toString() +} 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 66edb1caf..32a29a050 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 @@ -154,10 +154,18 @@ class MusicSorter( albums.forEach { if (it.name == "") it.name = albumPlaceholder } } - // Sort all music into + // Sort all music private fun finalizeMusic() { - genres.sortBy { it.name } - artists.sortBy { it.name } - albums.sortBy { it.name } + genres.sortWith( + compareBy(String.CASE_INSENSITIVE_ORDER, { it.name }) + ) + + artists.sortWith( + compareBy(String.CASE_INSENSITIVE_ORDER, { it.name }) + ) + + albums.sortWith( + compareBy(String.CASE_INSENSITIVE_ORDER, { it.name }) + ) } } diff --git a/app/src/main/res/drawable/ic_album.xml b/app/src/main/res/drawable/ic_album.xml new file mode 100644 index 000000000..5633d48c4 --- /dev/null +++ b/app/src/main/res/drawable/ic_album.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_artist.xml b/app/src/main/res/drawable/ic_artist.xml new file mode 100644 index 000000000..0c2cd720d --- /dev/null +++ b/app/src/main/res/drawable/ic_artist.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/artist_item.xml b/app/src/main/res/layout/artist_item.xml index 7c6a48da4..d18160d91 100644 --- a/app/src/main/res/layout/artist_item.xml +++ b/app/src/main/res/layout/artist_item.xml @@ -18,7 +18,16 @@ android:focusable="true" android:padding="@dimen/padding_medium"> - + @@ -41,10 +51,11 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceListItemSecondary" + android:layout_marginStart="@dimen/margin_medium" android:textColor="?android:attr/textColorSecondary" app:artistCounts="@{artist}" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintStart_toStartOf="parent" + app:layout_constraintStart_toEndOf="@+id/artist_image" app:layout_constraintTop_toBottomOf="@+id/artist_name" tools:text="2 Albums, 20 Songs" />