image: connect cover back up

This commit is contained in:
Alexander Capehart 2024-12-11 17:38:42 -07:00
parent 0ce3a11f82
commit 6d85f43304
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
2 changed files with 50 additions and 56 deletions

View file

@ -37,13 +37,13 @@ class CoilModule {
fun imageLoader(
@ApplicationContext context: Context,
keyer: CoverKeyer,
// factory: CoverFetcher.Factory
factory: CoverFetcher.Factory
) =
ImageLoader.Builder(context)
.components {
// Add fetchers for Music components to make them usable with ImageRequest
add(keyer)
// add(factory)
add(factory)
}
// Use our own crossfade with error drawable support
.transitionFactory(ErrorCrossfadeTransitionFactory())

View file

@ -23,11 +23,14 @@ import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import androidx.core.graphics.drawable.toDrawable
import coil3.ImageLoader
import coil3.asImage
import coil3.decode.DataSource
import coil3.decode.ImageSource
import coil3.fetch.FetchResult
import coil3.fetch.Fetcher
import coil3.fetch.ImageFetchResult
import coil3.fetch.SourceFetchResult
import coil3.key.Keyer
import coil3.request.Options
import coil3.size.Dimension
@ -35,7 +38,13 @@ import coil3.size.Size
import coil3.size.pxOrElse
import java.io.InputStream
import javax.inject.Inject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okio.FileSystem
import okio.buffer
import okio.source
import org.oxycblt.musikr.cover.Cover
import org.oxycblt.musikr.cover.StoredCovers
class CoverKeyer @Inject constructor() : Keyer<Cover> {
override fun key(data: Cover, options: Options) = "${data.key}&${options.size}"
@ -47,60 +56,46 @@ private constructor(
private val cover: Cover,
private val size: Size,
) : Fetcher {
private val storedCovers = StoredCovers.from(context, "covers")
override suspend fun fetch(): FetchResult? {
return null
// val streams =
// when (val cover = cover) {
// is Cover.Single -> listOfNotNull(coverRetriever.retrieve(cover))
// is Cover.Multi ->
// buildList {
// for (single in cover.all) {
// coverRetriever.retrieve(single)?.let { add(it) }
// if (size == 4) {
// break
// }
// }
// }
// }
val streams =
when (val cover = cover) {
is Cover.Single -> listOfNotNull(storedCovers.read(cover))
is Cover.Multi ->
buildList {
for (single in cover.all) {
storedCovers.read(single)?.let { add(it) }
if (size == 4) {
break
}
}
}
}
// We don't immediately check for mosaic feasibility from album count alone, as that
// does not factor in InputStreams failing to load. Instead, only check once we
// definitely have image data to use.
// if (streams.size == 4) {
// // Make sure we free the InputStreams once we've transformed them into a
if (streams.size == 4) {
// Make sure we free the InputStreams once we've transformed them into a
// mosaic.
// return createMosaic(streams, size).also {
// withContext(Dispatchers.IO) { streams.forEach(InputStream::close) }
// } // Not enough covers for a mosaic, take the first one (if that even
// exists)
// val first = streams.firstOrNull() ?: return null
//
// // All but the first stream will be unused, free their resources
// withContext(Dispatchers.IO) {
// for (i in 1 until streams.size) {
// streams[i].close()
// }
// }
//
// return SourceFetchResult(
// source = ImageSource(first.source().buffer(), FileSystem.SYSTEM, null),
// mimeType = null,
// dataSource = DataSource.DISK)
// }
return createMosaic(streams, size).also {
withContext(Dispatchers.IO) { streams.forEach(InputStream::close) }
}
}
// Not enough covers for a mosaic, take the first one (if that even exists)
val first = streams.firstOrNull() ?: return null
// // Not enough covers for a mosaic, take the first one (if that even exists)
// val first = streams.firstOrNull() ?: return null
//
// // All but the first stream will be unused, free their resources
// withContext(Dispatchers.IO) {
// for (i in 1 until streams.size) {
// streams[i].close()
// }
// }
//
// return SourceFetchResult(
// source = ImageSource(first.source().buffer(), FileSystem.SYSTEM, null),
// mimeType = null,
// dataSource = DataSource.DISK)
// All but the first stream will be unused, free their resources
withContext(Dispatchers.IO) {
for (i in 1 until streams.size) {
streams[i].close()
}
}
return SourceFetchResult(
source = ImageSource(first.source().buffer(), FileSystem.SYSTEM, null),
mimeType = null,
dataSource = DataSource.DISK)
}
/** Derived from phonograph: https://github.com/kabouzeid/Phonograph */
@ -154,9 +149,8 @@ private constructor(
return if (size.mod(2) > 0) size + 1 else size
}
// class Factory @Inject constructor(private val coverRetriever: CoverRetriever) :
// Fetcher.Factory<Cover> {
// override fun create(data: Cover, options: Options, imageLoader: ImageLoader) =
// CoverFetcher(options.context, data, options.size, coverRetriever)
// }
class Factory @Inject constructor() : Fetcher.Factory<Cover> {
override fun create(data: Cover, options: Options, imageLoader: ImageLoader) =
CoverFetcher(options.context, data, options.size)
}
}