From 2eaa9a209175c8986b9f3ec97a46f4c5a3529fb0 Mon Sep 17 00:00:00 2001 From: tzugen Date: Wed, 2 Jun 2021 15:21:45 +0200 Subject: [PATCH] Fix two bugs in the new image loader: 1. Id was checked for nullability, but it is actually an empty string in most cases where there is no Cover art. This lead to queries without id set. 2. Size was not respected by the new image loader. --- .../loader/image/CoverArtRequestHandler.kt | 3 +- .../subsonic/loader/image/RequestCreator.kt | 14 ++++++-- .../loader/image/SubsonicImageLoader.kt | 12 +++++-- .../subsonic/SubsonicImageLoaderProxy.kt | 36 ++++++++++++++----- 4 files changed, 49 insertions(+), 16 deletions(-) diff --git a/core/subsonic-api-image-loader/src/main/kotlin/org/moire/ultrasonic/subsonic/loader/image/CoverArtRequestHandler.kt b/core/subsonic-api-image-loader/src/main/kotlin/org/moire/ultrasonic/subsonic/loader/image/CoverArtRequestHandler.kt index 7e242479..dfeb5286 100644 --- a/core/subsonic-api-image-loader/src/main/kotlin/org/moire/ultrasonic/subsonic/loader/image/CoverArtRequestHandler.kt +++ b/core/subsonic-api-image-loader/src/main/kotlin/org/moire/ultrasonic/subsonic/loader/image/CoverArtRequestHandler.kt @@ -22,8 +22,9 @@ class CoverArtRequestHandler(private val apiClient: SubsonicAPIClient) : Request override fun load(request: Request, networkPolicy: Int): Result { val id = request.uri.getQueryParameter(QUERY_ID) ?: throw IllegalArgumentException("Nullable id") + val size = request.uri.getQueryParameter(SIZE)?.toLong() - val response = apiClient.getCoverArt(id) + val response = apiClient.getCoverArt(id, size) if (response.hasError() || response.stream == null) { throw IOException("${response.apiError}") } else { diff --git a/core/subsonic-api-image-loader/src/main/kotlin/org/moire/ultrasonic/subsonic/loader/image/RequestCreator.kt b/core/subsonic-api-image-loader/src/main/kotlin/org/moire/ultrasonic/subsonic/loader/image/RequestCreator.kt index 9cc6799a..78ae0b95 100644 --- a/core/subsonic-api-image-loader/src/main/kotlin/org/moire/ultrasonic/subsonic/loader/image/RequestCreator.kt +++ b/core/subsonic-api-image-loader/src/main/kotlin/org/moire/ultrasonic/subsonic/loader/image/RequestCreator.kt @@ -7,16 +7,24 @@ internal const val AUTHORITY = BuildConfig.LIBRARY_PACKAGE_NAME internal const val COVER_ART_PATH = "cover_art" internal const val AVATAR_PATH = "avatar" internal const val QUERY_ID = "id" +internal const val SIZE = "size" internal const val QUERY_USERNAME = "username" -internal fun createLoadCoverArtRequest(entityId: String): Uri = Uri.Builder() +/** + * Picasso.load() only accepts an URI as parameter. Therefore we create a bogus URI, in which + * we encode the data that we need in the RequestHandler. + */ +internal fun createLoadCoverArtRequest(config: ImageRequest.CoverArt): Uri = + Uri.Builder() .scheme(SCHEME) .authority(AUTHORITY) .appendPath(COVER_ART_PATH) - .appendQueryParameter(QUERY_ID, entityId) + .appendQueryParameter(QUERY_ID, config.entityId) + .appendQueryParameter(SIZE, config.size.toString()) .build() -internal fun createLoadAvatarRequest(username: String): Uri = Uri.Builder() +internal fun createLoadAvatarRequest(username: String): Uri = + Uri.Builder() .scheme(SCHEME) .authority(AUTHORITY) .appendPath(AVATAR_PATH) diff --git a/core/subsonic-api-image-loader/src/main/kotlin/org/moire/ultrasonic/subsonic/loader/image/SubsonicImageLoader.kt b/core/subsonic-api-image-loader/src/main/kotlin/org/moire/ultrasonic/subsonic/loader/image/SubsonicImageLoader.kt index 630bbc4a..7fa27f84 100644 --- a/core/subsonic-api-image-loader/src/main/kotlin/org/moire/ultrasonic/subsonic/loader/image/SubsonicImageLoader.kt +++ b/core/subsonic-api-image-loader/src/main/kotlin/org/moire/ultrasonic/subsonic/loader/image/SubsonicImageLoader.kt @@ -6,6 +6,9 @@ import com.squareup.picasso.Picasso import com.squareup.picasso.RequestCreator import org.moire.ultrasonic.api.subsonic.SubsonicAPIClient +// TODO: Caching doesn't work as expected because our query string varies. +// Need to use .stableKey() method + class SubsonicImageLoader( context: Context, apiClient: SubsonicAPIClient @@ -13,7 +16,7 @@ class SubsonicImageLoader( private val picasso = Picasso.Builder(context) .addRequestHandler(CoverArtRequestHandler(apiClient)) .addRequestHandler(AvatarRequestHandler(apiClient)) - .build().apply { setIndicatorsEnabled(BuildConfig.DEBUG) } + .build().apply { setIndicatorsEnabled(true) } fun load(request: ImageRequest) = when (request) { is ImageRequest.CoverArt -> loadCoverArt(request) @@ -21,9 +24,10 @@ class SubsonicImageLoader( } private fun loadCoverArt(request: ImageRequest.CoverArt) { - picasso.load(createLoadCoverArtRequest(request.entityId)) + picasso.load(createLoadCoverArtRequest(request)) .addPlaceholder(request) .addError(request) + .stableKey("${request.entityId}-${request.size}" ) .into(request.imageView) } @@ -31,6 +35,7 @@ class SubsonicImageLoader( picasso.load(createLoadAvatarRequest(request.username)) .addPlaceholder(request) .addError(request) + .stableKey(request.username) .into(request.imageView) } @@ -59,8 +64,9 @@ sealed class ImageRequest( class CoverArt( val entityId: String, imageView: ImageView, + val size: Int, placeHolderDrawableRes: Int? = null, - errorDrawableRes: Int? = null + errorDrawableRes: Int? = null, ) : ImageRequest( placeHolderDrawableRes, errorDrawableRes, diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/SubsonicImageLoaderProxy.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/SubsonicImageLoaderProxy.kt index 6d0d2b99..2464dfcc 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/SubsonicImageLoaderProxy.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/SubsonicImageLoaderProxy.kt @@ -2,12 +2,15 @@ package org.moire.ultrasonic.subsonic import android.view.View import android.widget.ImageView +import androidx.core.content.res.ResourcesCompat import org.moire.ultrasonic.R +import org.moire.ultrasonic.app.UApp import org.moire.ultrasonic.domain.MusicDirectory import org.moire.ultrasonic.subsonic.loader.image.ImageRequest import org.moire.ultrasonic.subsonic.loader.image.SubsonicImageLoader import org.moire.ultrasonic.util.ImageLoader import org.moire.ultrasonic.util.LegacyImageLoader +import org.moire.ultrasonic.util.Util /** * Temporary proxy between new [SubsonicImageLoader] and [ImageLoader] interface and old @@ -19,6 +22,11 @@ class SubsonicImageLoaderProxy( legacyImageLoader: LegacyImageLoader, private val subsonicImageLoader: SubsonicImageLoader ) : ImageLoader by legacyImageLoader { + + private var imageSizeLarge = Util.getMaxDisplayMetric() + private var imageSizeDefault = 0 + + override fun loadImage( view: View?, entry: MusicDirectory.Entry?, @@ -40,16 +48,18 @@ class SubsonicImageLoaderProxy( defaultResourceId: Int ) { val id = entry?.coverArt + var requestedSize = size val unknownImageId = if (defaultResourceId == -1) R.drawable.unknown_album else defaultResourceId - if (id != null && - view != null && - view is ImageView - ) { + if (requestedSize <= 0) { + requestedSize = if (large) imageSizeLarge else imageSizeDefault + } + + if (id != null && id.isNotEmpty() && view is ImageView) { val request = ImageRequest.CoverArt( - id, view, + id, view, requestedSize, placeHolderDrawableRes = unknownImageId, errorDrawableRes = unknownImageId ) @@ -65,10 +75,7 @@ class SubsonicImageLoaderProxy( crossFade: Boolean, highQuality: Boolean ) { - if (username != null && - view != null && - view is ImageView - ) { + if (username != null && username.isNotEmpty() && view is ImageView) { val request = ImageRequest.Avatar( username, view, placeHolderDrawableRes = R.drawable.ic_contact_picture, @@ -77,4 +84,15 @@ class SubsonicImageLoaderProxy( subsonicImageLoader.load(request) } } + + init { + val default = ResourcesCompat.getDrawable( + UApp.applicationContext().resources, R.drawable.unknown_album, null) + + // Determine the density-dependent image sizes by taking the fallback album + // image and querying its size. + if (default != null) { + imageSizeDefault = default.intrinsicHeight + } + } }