image: use di w/coil

Use dependency injection with Coil.

This allows me to use the coil-base artifact which should remove a bit
of superfluous dexcode, assuming dagger uses less. It probably doesn't.
This commit is contained in:
Alexander Capehart 2023-02-12 19:07:00 -07:00
parent 63e5a7ee69
commit dd2017c510
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
13 changed files with 112 additions and 81 deletions

View file

@ -113,7 +113,7 @@ dependencies {
implementation fileTree(dir: "libs", include: ["extension-*.aar"]) implementation fileTree(dir: "libs", include: ["extension-*.aar"])
// Image loading // Image loading
implementation "io.coil-kt:coil:2.1.0" implementation "io.coil-kt:coil-base:2.1.0"
// Material // Material
// Locked below 1.7.0-alpha03 to avoid the same ripple bug // Locked below 1.7.0-alpha03 to avoid the same ripple bug

View file

@ -22,17 +22,9 @@ import android.content.Intent
import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat import androidx.core.graphics.drawable.IconCompat
import coil.ImageLoader
import coil.ImageLoaderFactory
import coil.request.CachePolicy
import dagger.hilt.android.HiltAndroidApp import dagger.hilt.android.HiltAndroidApp
import javax.inject.Inject import javax.inject.Inject
import org.oxycblt.auxio.image.ImageSettings import org.oxycblt.auxio.image.ImageSettings
import org.oxycblt.auxio.image.extractor.AlbumCoverFetcher
import org.oxycblt.auxio.image.extractor.ArtistImageFetcher
import org.oxycblt.auxio.image.extractor.ErrorCrossfadeTransitionFactory
import org.oxycblt.auxio.image.extractor.GenreImageFetcher
import org.oxycblt.auxio.image.extractor.MusicKeyer
import org.oxycblt.auxio.playback.PlaybackSettings import org.oxycblt.auxio.playback.PlaybackSettings
import org.oxycblt.auxio.ui.UISettings import org.oxycblt.auxio.ui.UISettings
@ -41,7 +33,7 @@ import org.oxycblt.auxio.ui.UISettings
* @author Alexander Capehart (OxygenCobalt) * @author Alexander Capehart (OxygenCobalt)
*/ */
@HiltAndroidApp @HiltAndroidApp
class Auxio : Application(), ImageLoaderFactory { class Auxio : Application() {
@Inject lateinit var imageSettings: ImageSettings @Inject lateinit var imageSettings: ImageSettings
@Inject lateinit var playbackSettings: PlaybackSettings @Inject lateinit var playbackSettings: PlaybackSettings
@Inject lateinit var uiSettings: UISettings @Inject lateinit var uiSettings: UISettings
@ -68,22 +60,6 @@ class Auxio : Application(), ImageLoaderFactory {
.build())) .build()))
} }
override fun newImageLoader() =
ImageLoader.Builder(applicationContext)
.components {
// Add fetchers for Music components to make them usable with ImageRequest
add(MusicKeyer())
add(AlbumCoverFetcher.SongFactory())
add(AlbumCoverFetcher.AlbumFactory())
add(ArtistImageFetcher.Factory())
add(GenreImageFetcher.Factory())
}
// Use our own crossfade with error drawable support
.transitionFactory(ErrorCrossfadeTransitionFactory())
// Not downloading anything, so no disk-caching
.diskCachePolicy(CachePolicy.DISABLED)
.build()
companion object { companion object {
/** The [Intent] name for the "Shuffle All" shortcut. */ /** The [Intent] name for the "Shuffle All" shortcut. */
const val INTENT_KEY_SHORTCUT_SHUFFLE = BuildConfig.APPLICATION_ID + ".action.SHUFFLE_ALL" const val INTENT_KEY_SHORTCUT_SHUFFLE = BuildConfig.APPLICATION_ID + ".action.SHUFFLE_ALL"

View file

@ -20,10 +20,12 @@ package org.oxycblt.auxio.image
import android.content.Context import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import coil.imageLoader import coil.ImageLoader
import coil.request.Disposable import coil.request.Disposable
import coil.request.ImageRequest import coil.request.ImageRequest
import coil.size.Size import coil.size.Size
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import org.oxycblt.auxio.image.extractor.SquareFrameTransform import org.oxycblt.auxio.image.extractor.SquareFrameTransform
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
@ -38,7 +40,12 @@ import org.oxycblt.auxio.music.Song
* @param context [Context] required to load images. * @param context [Context] required to load images.
* @author Alexander Capehart (OxygenCobalt) * @author Alexander Capehart (OxygenCobalt)
*/ */
class BitmapProvider(private val context: Context) { class BitmapProvider
@Inject
constructor(
@ApplicationContext private val context: Context,
private val imageLoader: ImageLoader
) {
/** /**
* An extension of [Disposable] with an additional [Target] to deliver the final [Bitmap] to. * An extension of [Disposable] with an additional [Target] to deliver the final [Bitmap] to.
*/ */
@ -94,7 +101,7 @@ class BitmapProvider(private val context: Context) {
onSuccess = { onSuccess = {
synchronized(this) { synchronized(this) {
if (currentHandle == handle) { if (currentHandle == handle) {
// Has not been superceded by a new request, can deliver // Has not been superseded by a new request, can deliver
// this result. // this result.
target.onCompleted(it.toBitmap()) target.onCompleted(it.toBitmap())
} }
@ -103,13 +110,13 @@ class BitmapProvider(private val context: Context) {
onError = { onError = {
synchronized(this) { synchronized(this) {
if (currentHandle == handle) { if (currentHandle == handle) {
// Has not been superceded by a new request, can deliver // Has not been superseded by a new request, can deliver
// this result. // this result.
target.onCompleted(null) target.onCompleted(null)
} }
} }
}) })
currentRequest = Request(context.imageLoader.enqueue(imageRequest.build()), target) currentRequest = Request(imageLoader.enqueue(imageRequest.build()), target)
} }
/** Release this instance, cancelling any currently running operations. */ /** Release this instance, cancelling any currently running operations. */

View file

@ -17,13 +17,52 @@
package org.oxycblt.auxio.image package org.oxycblt.auxio.image
import android.content.Context
import coil.ImageLoader
import coil.request.CachePolicy
import dagger.Binds import dagger.Binds
import dagger.Module import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
import org.oxycblt.auxio.image.extractor.AlbumCoverFetcher
import org.oxycblt.auxio.image.extractor.ArtistImageFetcher
import org.oxycblt.auxio.image.extractor.ErrorCrossfadeTransitionFactory
import org.oxycblt.auxio.image.extractor.GenreImageFetcher
import org.oxycblt.auxio.image.extractor.MusicKeyer
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
interface ImageModule { interface ImageModule {
@Binds fun settings(imageSettings: ImageSettingsImpl): ImageSettings @Binds fun settings(imageSettings: ImageSettingsImpl): ImageSettings
} }
@Module
@InstallIn(SingletonComponent::class)
class CoilModule {
@Singleton
@Provides
fun imageLoader(
@ApplicationContext context: Context,
songFactory: AlbumCoverFetcher.SongFactory,
albumFactory: AlbumCoverFetcher.AlbumFactory,
artistFactory: ArtistImageFetcher.Factory,
genreFactory: GenreImageFetcher.Factory
) =
ImageLoader.Builder(context)
.components {
// Add fetchers for Music components to make them usable with ImageRequest
add(MusicKeyer())
add(songFactory)
add(albumFactory)
add(artistFactory)
add(genreFactory)
}
// Use our own crossfade with error drawable support
.transitionFactory(ErrorCrossfadeTransitionFactory())
// Not downloading anything, so no disk-caching
.diskCachePolicy(CachePolicy.DISABLED)
.build()
}

View file

@ -37,14 +37,6 @@ interface ImageSettings : Settings<ImageSettings.Listener> {
/** Called when [coverMode] changes. */ /** Called when [coverMode] changes. */
fun onCoverModeChanged() {} fun onCoverModeChanged() {}
} }
companion object {
/**
* Get a framework-backed implementation.
* @param context [Context] required.
*/
fun from(context: Context): ImageSettings = ImageSettingsImpl(context)
}
} }
class ImageSettingsImpl @Inject constructor(@ApplicationContext context: Context) : class ImageSettingsImpl @Inject constructor(@ApplicationContext context: Context) :

View file

@ -29,8 +29,9 @@ import androidx.annotation.StringRes
import androidx.appcompat.widget.AppCompatImageView import androidx.appcompat.widget.AppCompatImageView
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.drawable.DrawableCompat import androidx.core.graphics.drawable.DrawableCompat
import coil.dispose import coil.ImageLoader
import coil.load import coil.request.ImageRequest
import coil.util.CoilUtils
import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.MaterialShapeDrawable
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject import javax.inject.Inject
@ -60,6 +61,7 @@ class StyledImageView
@JvmOverloads @JvmOverloads
constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) : constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) :
AppCompatImageView(context, attrs, defStyleAttr) { AppCompatImageView(context, attrs, defStyleAttr) {
@Inject lateinit var imageLoader: ImageLoader
@Inject lateinit var uiSettings: UISettings @Inject lateinit var uiSettings: UISettings
init { init {
@ -125,13 +127,16 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
* field for the name of the [Music]. * field for the name of the [Music].
*/ */
private fun bindImpl(music: Music, @DrawableRes errorRes: Int, @StringRes descRes: Int) { private fun bindImpl(music: Music, @DrawableRes errorRes: Int, @StringRes descRes: Int) {
val request =
ImageRequest.Builder(context)
.data(music)
.error(StyledDrawable(context, context.getDrawableCompat(errorRes)))
.transformations(SquareFrameTransform.INSTANCE)
.target(this)
.build()
// Dispose of any previous image request and load a new image. // Dispose of any previous image request and load a new image.
dispose() CoilUtils.dispose(this)
load(music) { imageLoader.enqueue(request)
error(StyledDrawable(context, context.getDrawableCompat(errorRes)))
transformations(SquareFrameTransform.INSTANCE)
}
// Update the content description to the specified resource. // Update the content description to the specified resource.
contentDescription = context.getString(descRes, music.resolveName(context)) contentDescription = context.getString(descRes, music.resolveName(context))
} }

View file

@ -27,9 +27,11 @@ import coil.fetch.SourceResult
import coil.key.Keyer import coil.key.Keyer
import coil.request.Options import coil.request.Options
import coil.size.Size import coil.size.Size
import javax.inject.Inject
import kotlin.math.min import kotlin.math.min
import okio.buffer import okio.buffer
import okio.source import okio.source
import org.oxycblt.auxio.image.ImageSettings
import org.oxycblt.auxio.list.Sort import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Artist
@ -57,9 +59,13 @@ class MusicKeyer : Keyer<Music> {
* @author Alexander Capehart (OxygenCobalt) * @author Alexander Capehart (OxygenCobalt)
*/ */
class AlbumCoverFetcher class AlbumCoverFetcher
private constructor(private val context: Context, private val album: Album) : Fetcher { private constructor(
private val context: Context,
private val imageSettings: ImageSettings,
private val album: Album
) : Fetcher {
override suspend fun fetch(): FetchResult? = override suspend fun fetch(): FetchResult? =
Covers.fetch(context, album)?.run { Covers.fetch(context, imageSettings, album)?.run {
SourceResult( SourceResult(
source = ImageSource(source().buffer(), context), source = ImageSource(source().buffer(), context),
mimeType = null, mimeType = null,
@ -67,15 +73,17 @@ private constructor(private val context: Context, private val album: Album) : Fe
} }
/** A [Fetcher.Factory] implementation that works with [Song]s. */ /** A [Fetcher.Factory] implementation that works with [Song]s. */
class SongFactory : Fetcher.Factory<Song> { class SongFactory @Inject constructor(private val imageSettings: ImageSettings) :
Fetcher.Factory<Song> {
override fun create(data: Song, options: Options, imageLoader: ImageLoader) = override fun create(data: Song, options: Options, imageLoader: ImageLoader) =
AlbumCoverFetcher(options.context, data.album) AlbumCoverFetcher(options.context, imageSettings, data.album)
} }
/** A [Fetcher.Factory] implementation that works with [Album]s. */ /** A [Fetcher.Factory] implementation that works with [Album]s. */
class AlbumFactory : Fetcher.Factory<Album> { class AlbumFactory @Inject constructor(private val imageSettings: ImageSettings) :
Fetcher.Factory<Album> {
override fun create(data: Album, options: Options, imageLoader: ImageLoader) = override fun create(data: Album, options: Options, imageLoader: ImageLoader) =
AlbumCoverFetcher(options.context, data) AlbumCoverFetcher(options.context, imageSettings, data)
} }
} }
@ -86,20 +94,23 @@ private constructor(private val context: Context, private val album: Album) : Fe
class ArtistImageFetcher class ArtistImageFetcher
private constructor( private constructor(
private val context: Context, private val context: Context,
private val imageSettings: ImageSettings,
private val size: Size, private val size: Size,
private val artist: Artist private val artist: Artist
) : Fetcher { ) : Fetcher {
override suspend fun fetch(): FetchResult? { override suspend fun fetch(): FetchResult? {
// Pick the "most prominent" albums (i.e albums with the most songs) to show in the image. // Pick the "most prominent" albums (i.e albums with the most songs) to show in the image.
val albums = Sort(Sort.Mode.ByCount, Sort.Direction.DESCENDING).albums(artist.albums) val albums = Sort(Sort.Mode.ByCount, Sort.Direction.DESCENDING).albums(artist.albums)
val results = albums.mapAtMostNotNull(4) { album -> Covers.fetch(context, album) } val results =
albums.mapAtMostNotNull(4) { album -> Covers.fetch(context, imageSettings, album) }
return Images.createMosaic(context, results, size) return Images.createMosaic(context, results, size)
} }
/** [Fetcher.Factory] implementation. */ /** [Fetcher.Factory] implementation. */
class Factory : Fetcher.Factory<Artist> { class Factory @Inject constructor(private val imageSettings: ImageSettings) :
Fetcher.Factory<Artist> {
override fun create(data: Artist, options: Options, imageLoader: ImageLoader) = override fun create(data: Artist, options: Options, imageLoader: ImageLoader) =
ArtistImageFetcher(options.context, options.size, data) ArtistImageFetcher(options.context, imageSettings, options.size, data)
} }
} }
@ -110,18 +121,20 @@ private constructor(
class GenreImageFetcher class GenreImageFetcher
private constructor( private constructor(
private val context: Context, private val context: Context,
private val imageSettings: ImageSettings,
private val size: Size, private val size: Size,
private val genre: Genre private val genre: Genre
) : Fetcher { ) : Fetcher {
override suspend fun fetch(): FetchResult? { override suspend fun fetch(): FetchResult? {
val results = genre.albums.mapAtMostNotNull(4) { Covers.fetch(context, it) } val results = genre.albums.mapAtMostNotNull(4) { Covers.fetch(context, imageSettings, it) }
return Images.createMosaic(context, results, size) return Images.createMosaic(context, results, size)
} }
/** [Fetcher.Factory] implementation. */ /** [Fetcher.Factory] implementation. */
class Factory : Fetcher.Factory<Genre> { class Factory @Inject constructor(private val imageSettings: ImageSettings) :
Fetcher.Factory<Genre> {
override fun create(data: Genre, options: Options, imageLoader: ImageLoader) = override fun create(data: Genre, options: Options, imageLoader: ImageLoader) =
GenreImageFetcher(options.context, options.size, data) GenreImageFetcher(options.context, imageSettings, options.size, data)
} }
} }

View file

@ -42,13 +42,14 @@ object Covers {
/** /**
* Fetch an album cover, respecting the current cover configuration. * Fetch an album cover, respecting the current cover configuration.
* @param context [Context] required to load the image. * @param context [Context] required to load the image.
* @param imageSettings [ImageSettings] required to obtain configuration information.
* @param album [Album] to load the cover from. * @param album [Album] to load the cover from.
* @return An [InputStream] of image data if the cover loading was successful, null if the cover * @return An [InputStream] of image data if the cover loading was successful, null if the cover
* loading failed or should not occur. * loading failed or should not occur.
*/ */
suspend fun fetch(context: Context, album: Album): InputStream? { suspend fun fetch(context: Context, imageSettings: ImageSettings, album: Album): InputStream? {
return try { return try {
when (ImageSettings.from(context).coverMode) { when (imageSettings.coverMode) {
CoverMode.OFF -> null CoverMode.OFF -> null
CoverMode.MEDIA_STORE -> fetchMediaStoreCovers(context, album) CoverMode.MEDIA_STORE -> fetchMediaStoreCovers(context, album)
CoverMode.QUALITY -> fetchQualityCovers(context, album) CoverMode.QUALITY -> fetchQualityCovers(context, album)

View file

@ -25,7 +25,7 @@ import android.os.IBinder
import android.os.Looper import android.os.Looper
import android.os.PowerManager import android.os.PowerManager
import android.provider.MediaStore import android.provider.MediaStore
import coil.imageLoader import coil.ImageLoader
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -68,6 +68,7 @@ class IndexerService : Service(), Indexer.Controller, MusicSettings.Listener {
private lateinit var wakeLock: PowerManager.WakeLock private lateinit var wakeLock: PowerManager.WakeLock
private lateinit var indexerContentObserver: SystemContentObserver private lateinit var indexerContentObserver: SystemContentObserver
@Inject lateinit var musicSettings: MusicSettings @Inject lateinit var musicSettings: MusicSettings
@Inject lateinit var imageLoader: ImageLoader
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()

View file

@ -52,8 +52,9 @@ class MediaSessionComponent
@Inject @Inject
constructor( constructor(
@ApplicationContext private val context: Context, @ApplicationContext private val context: Context,
private val bitmapProvider: BitmapProvider,
private val playbackManager: PlaybackStateManager, private val playbackManager: PlaybackStateManager,
private val playbackSettings: PlaybackSettings private val playbackSettings: PlaybackSettings,
) : ) :
MediaSessionCompat.Callback(), MediaSessionCompat.Callback(),
PlaybackStateManager.Listener, PlaybackStateManager.Listener,
@ -66,7 +67,6 @@ constructor(
} }
private val notification = NotificationComponent(context, mediaSession.sessionToken) private val notification = NotificationComponent(context, mediaSession.sessionToken)
private val provider = BitmapProvider(context)
private var listener: Listener? = null private var listener: Listener? = null
@ -98,7 +98,7 @@ constructor(
*/ */
fun release() { fun release() {
listener = null listener = null
provider.release() bitmapProvider.release()
playbackSettings.unregisterListener(this) playbackSettings.unregisterListener(this)
playbackManager.removeListener(this) playbackManager.removeListener(this)
mediaSession.apply { mediaSession.apply {
@ -148,7 +148,7 @@ constructor(
override fun onStateChanged(state: InternalPlayer.State) { override fun onStateChanged(state: InternalPlayer.State) {
invalidateSessionState() invalidateSessionState()
notification.updatePlaying(playbackManager.playerState.isPlaying) notification.updatePlaying(playbackManager.playerState.isPlaying)
if (!provider.isBusy) { if (!bitmapProvider.isBusy) {
listener?.onPostNotification(notification) listener?.onPostNotification(notification)
} }
} }
@ -321,7 +321,7 @@ constructor(
// We are normally supposed to use URIs for album art, but that removes some of the // We are normally supposed to use URIs for album art, but that removes some of the
// nice things we can do like square cropping or high quality covers. Instead, // nice things we can do like square cropping or high quality covers. Instead,
// we load a full-size bitmap into the media session and take the performance hit. // we load a full-size bitmap into the media session and take the performance hit.
provider.load( bitmapProvider.load(
song, song,
object : BitmapProvider.Target { object : BitmapProvider.Target {
override fun onCompleted(bitmap: Bitmap?) { override fun onCompleted(bitmap: Bitmap?) {
@ -416,7 +416,7 @@ constructor(
else -> notification.updateRepeatMode(playbackManager.repeatMode) else -> notification.updateRepeatMode(playbackManager.repeatMode)
} }
if (!provider.isBusy) { if (!bitmapProvider.isBusy) {
listener?.onPostNotification(notification) listener?.onPostNotification(notification)
} }
} }

View file

@ -19,7 +19,9 @@ package org.oxycblt.auxio.settings.categories
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.preference.Preference import androidx.preference.Preference
import coil.Coil import coil.ImageLoader
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.settings.BasePreferenceFragment import org.oxycblt.auxio.settings.BasePreferenceFragment
import org.oxycblt.auxio.settings.ui.WrappedDialogPreference import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
@ -28,7 +30,10 @@ import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
* "Content" settings. * "Content" settings.
* @author Alexander Capehart (OxygenCobalt) * @author Alexander Capehart (OxygenCobalt)
*/ */
@AndroidEntryPoint
class MusicPreferenceFragment : BasePreferenceFragment(R.xml.preferences_music) { class MusicPreferenceFragment : BasePreferenceFragment(R.xml.preferences_music) {
@Inject lateinit var imageLoader: ImageLoader
override fun onOpenDialogPreference(preference: WrappedDialogPreference) { override fun onOpenDialogPreference(preference: WrappedDialogPreference) {
if (preference.key == getString(R.string.set_key_separators)) { if (preference.key == getString(R.string.set_key_separators)) {
findNavController().navigate(MusicPreferenceFragmentDirections.goToSeparatorsDialog()) findNavController().navigate(MusicPreferenceFragmentDirections.goToSeparatorsDialog())
@ -39,7 +44,7 @@ class MusicPreferenceFragment : BasePreferenceFragment(R.xml.preferences_music)
if (preference.key == getString(R.string.set_key_cover_mode)) { if (preference.key == getString(R.string.set_key_cover_mode)) {
preference.onPreferenceChangeListener = preference.onPreferenceChangeListener =
Preference.OnPreferenceChangeListener { _, _ -> Preference.OnPreferenceChangeListener { _, _ ->
Coil.imageLoader(requireContext()).memoryCache?.clear() imageLoader.memoryCache?.clear()
true true
} }
} }

View file

@ -46,14 +46,6 @@ interface UISettings : Settings<UISettings.Listener> {
/** Called when [roundMode] changes. */ /** Called when [roundMode] changes. */
fun onRoundModeChanged() fun onRoundModeChanged()
} }
companion object {
/**
* Get a framework-backed implementation.
* @param context [Context] required.
*/
fun from(context: Context): UISettings = UISettingsImpl(context)
}
} }
class UISettingsImpl @Inject constructor(@ApplicationContext context: Context) : class UISettingsImpl @Inject constructor(@ApplicationContext context: Context) :

View file

@ -48,11 +48,11 @@ class WidgetComponent
constructor( constructor(
@ApplicationContext private val context: Context, @ApplicationContext private val context: Context,
private val imageSettings: ImageSettings, private val imageSettings: ImageSettings,
private val bitmapProvider: BitmapProvider,
private val playbackManager: PlaybackStateManager, private val playbackManager: PlaybackStateManager,
private val uiSettings: UISettings private val uiSettings: UISettings
) : PlaybackStateManager.Listener, UISettings.Listener, ImageSettings.Listener { ) : PlaybackStateManager.Listener, UISettings.Listener, ImageSettings.Listener {
private val widgetProvider = WidgetProvider() private val widgetProvider = WidgetProvider()
private val provider = BitmapProvider(context)
init { init {
playbackManager.addListener(this) playbackManager.addListener(this)
@ -74,7 +74,7 @@ constructor(
val repeatMode = playbackManager.repeatMode val repeatMode = playbackManager.repeatMode
val isShuffled = playbackManager.queue.isShuffled val isShuffled = playbackManager.queue.isShuffled
provider.load( bitmapProvider.load(
song, song,
object : BitmapProvider.Target { object : BitmapProvider.Target {
override fun onConfigRequest(builder: ImageRequest.Builder): ImageRequest.Builder { override fun onConfigRequest(builder: ImageRequest.Builder): ImageRequest.Builder {
@ -112,7 +112,7 @@ constructor(
/** Release this instance, preventing any further events from updating the widget instances. */ /** Release this instance, preventing any further events from updating the widget instances. */
fun release() { fun release() {
provider.release() bitmapProvider.release()
imageSettings.unregisterListener(this) imageSettings.unregisterListener(this)
playbackManager.removeListener(this) playbackManager.removeListener(this)
uiSettings.unregisterListener(this) uiSettings.unregisterListener(this)