Add artist images
Add artist images back, now with proper mosaics.
This commit is contained in:
parent
016d664e51
commit
a93c0f4af3
6 changed files with 177 additions and 11 deletions
|
@ -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<Uri>()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<List<Uri>> {
|
||||
override suspend fun fetch(
|
||||
pool: BitmapPool,
|
||||
data: List<Uri>,
|
||||
size: Size,
|
||||
options: Options
|
||||
): FetchResult {
|
||||
val streams = mutableListOf<InputStream>()
|
||||
|
||||
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<Uri>): String? = data.toString()
|
||||
}
|
|
@ -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 })
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
11
app/src/main/res/drawable/ic_album.xml
Normal file
11
app/src/main/res/drawable/ic_album.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorPrimary">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,16.5c-2.49,0 -4.5,-2.01 -4.5,-4.5S9.51,7.5 12,7.5s4.5,2.01 4.5,4.5 -2.01,4.5 -4.5,4.5zM12,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1 -0.45,-1 -1,-1z" />
|
||||
</vector>
|
11
app/src/main/res/drawable/ic_artist.xml
Normal file
11
app/src/main/res/drawable/ic_artist.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorPrimary">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M9,11.75c-0.69,0 -1.25,0.56 -1.25,1.25s0.56,1.25 1.25,1.25 1.25,-0.56 1.25,-1.25 -0.56,-1.25 -1.25,-1.25zM15,11.75c-0.69,0 -1.25,0.56 -1.25,1.25s0.56,1.25 1.25,1.25 1.25,-0.56 1.25,-1.25 -0.56,-1.25 -1.25,-1.25zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8 0,-0.29 0.02,-0.58 0.05,-0.86 2.36,-1.05 4.23,-2.98 5.21,-5.37C11.07,8.33 14.05,10 17.42,10c0.78,0 1.53,-0.09 2.25,-0.26 0.21,0.71 0.33,1.47 0.33,2.26 0,4.41 -3.59,8 -8,8z" />
|
||||
</vector>
|
|
@ -18,7 +18,16 @@
|
|||
android:focusable="true"
|
||||
android:padding="@dimen/padding_medium">
|
||||
|
||||
<!-- TODO: Artist images -->
|
||||
<ImageView
|
||||
android:id="@+id/artist_image"
|
||||
android:layout_width="@dimen/cover_size_normal"
|
||||
android:layout_height="@dimen/cover_size_normal"
|
||||
app:artistImage="@{artist}"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@tools:sample/backgrounds/scenic"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/artist_name"
|
||||
|
@ -27,11 +36,12 @@
|
|||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:text="@{artist.name}"
|
||||
android:layout_marginStart="@dimen/margin_medium"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
app:layout_constraintBottom_toTopOf="@+id/album_song_count"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/artist_image"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
tools:text="Artist Name" />
|
||||
|
@ -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" />
|
||||
|
||||
|
|
Loading…
Reference in a new issue