🍂 Jetpack Compose image loading library which can fetch and display network images using Glide, Coil, and Fresco.

Overview

landscapist

Google
License API Build Status Android Weekly Medium Profile

🍂 Jetpack Compose image loading library which can fetch and display network images using Glide, Coil, Fresco

Who's using Landscapist?

See who's using Landscapist.

Usecase

You can see the use cases of this library in the below repositories.

  • DisneyCompose - 🧸 A demo Disney app using Jetpack Compose and Hilt based on modern Android tech-stacks and MVVM architecture.
  • MovieCompose - 🎞 A demo movie app using Jetpack Compose and Hilt based on modern Android tech stacks.
Glide

Glide

Maven Central

Add below codes to your root build.gradle file (not your module build.gradle file).

allprojects {
    repositories {
        mavenCentral()
    }
}

Also add a dependency code to your module's build.gradle file.

dependencies {
    implementation "com.github.skydoves:landscapist-glide:1.3.6"
}

Usage

We can request and load images simply using a GlideImage composable function.

GlideImage(
  imageModel = imageUrl,
  // Crop, Fit, Inside, FillHeight, FillWidth, None
  contentScale = ContentScale.Crop,
  // shows an image with a circular revealed animation.
  circularReveal = CircularReveal(duration = 250),
  // shows a placeholder ImageBitmap when loading.
  placeHolder = ImageBitmap.imageResource(R.drawable.placeholder),
  // shows an error ImageBitmap when the request failed.
  error = ImageBitmap.imageResource(R.drawable.error)
)

RequestOptions and TransitionOptions

We can customize our request options using RequestOptions and TransitionOptions for applying caching strategies, loading transformations.

GlideImage(
  imageModel = poster.poster,
  requestOptions = RequestOptions()
    .override(256, 256)
    .diskCacheStrategy(DiskCacheStrategy.ALL)
    .centerCrop(),
  contentScale = ContentScale.Crop,
  modifier = modifier,
  alignment = Alignment.Center,
)

RequestBuilder

Also we can request image by passing a RequestBuilder. RequestBuilder is the backbone of the request in Glide and is responsible for bringing your options together with your requested url or model to start a new load.

GlideImage(
  imageModel = poster.poster,
  requestBuilder = Glide.with(LocalContext.current.applicationContext).asDrawable(),
  modifier = Modifier.constrainAs(image) {
    centerHorizontallyTo(parent)
    top.linkTo(parent.top)
  }.aspectRatio(0.8f)
)

LocalGlideRequestOptions

We can provide the same instance of the RequestOptions in the composable hierarchy.

// customize the RequestOptions as needed
val requestOptions = RequestOptions()
    .override(300, 300)
    .circleCrop()

CompositionLocalProvider(LocalGlideRequestOptions provides requestOptions) {
  // This will automatically use the value of current RequestOptions in the hierarchy.
  GlideImage(
    imageModel = ...
  )
}

Composable loading, success, failure

We can create our own composable functions following requesting states.
Here is an example that shows a progress indicator when loading an image,
After complete requesting, the indicator will be gone and a content image will be shown.
If the request failed (e.g. network error, wrong destination), error text will be shown.

 GlideImage(
 imageModel = poster.poster,
 modifier = modifier,
 // shows a progress indicator when loading an image.
 loading = {
   ConstraintLayout(
     modifier = Modifier.fillMaxSize()
   ) {
     val indicator = createRef()
     CircularProgressIndicator(
       modifier = Modifier.constrainAs(indicator) {
         top.linkTo(parent.top)
         bottom.linkTo(parent.bottom)
        start.linkTo(parent.start)
        end.linkTo(parent.end)
       }
     )
   }
 },
 // shows an error text message when request failed.
 failure = {
   Text(text = "image request failed.")
 })
Fresco

Coil

Maven Central
Add a dependency code to your module's build.gradle file.

" } ">
dependencies {
    implementation "com.github.skydoves:landscapist-coil:
   
    "
   
}

Usage

We can request and load images simply using a CoilImage composable function.

CoilImage(
  imageModel = imageUrl,
  // Crop, Fit, Inside, FillHeight, FillWidth, None
  contentScale = ContentScale.Crop,
  // shows an image with a circular revealed animation.
  circularReveal = CircularReveal(duration = 250),
  // shows a placeholder ImageBitmap when loading.
  placeHolder = ImageBitmap.imageResource(R.drawable.placeholder),
  // shows an error ImageBitmap when the request failed.
  error = ImageBitmap.imageResource(R.drawable.error)
)

ImageRequest and ImageLoader

We can customize request options using ImageRequest and ImageLoader for providing all the necessary information for loading images like caching strategies and transformations.

CoilImage(
  imageRequest = ImageRequest.Builder(LocalContext.current)
    .data(poster.poster)
    .crossfade(true)
    .build(),
  imageLoader = ImageLoader.Builder(LocalContext.current)
    .availableMemoryPercentage(0.25)
    .crossfade(true)
    .build(),
  contentScale = ContentScale.Crop,
  modifier = modifier,
  alignment = Alignment.Center,
)

Composable loading, success, failure

We can create our own composable functions following requesting states. Here is an example that shows a progress indicator when loading an image, After complete requesting, the indicator will be gone and a content image will be shown. If the request failed (e.g. network error, wrong destination), error text will be shown.

CoilImage(
  imageModel = poster.poster,
  modifier = Modifier.constrainAs(image) {
    centerHorizontallyTo(parent)
    top.linkTo(parent.top)
  }.aspectRatio(0.8f),
  // shows a progress indicator when loading an image.
  loading = {
    ConstraintLayout(
      modifier = Modifier.fillMaxSize()
    ) {
      val indicator = createRef()
      CircularProgressIndicator(
        modifier = Modifier.constrainAs(indicator) {
          top.linkTo(parent.top)
          bottom.linkTo(parent.bottom)
          start.linkTo(parent.start)
          end.linkTo(parent.end)
        }
      )
    }
  },
  // shows an error text message when request failed.
  failure = {
    Text(text = "image request failed.")
  })

Shimmer effect

We can give a shimmering effect when loading images using a ShimmerParams. We can also use ShimmerParams in GlideImage and FrescoImage.

 CoilImage(
 imageModel = poster.poster,
 modifier = modifier,
 // shows a shimmering effect when loading an image.
 shimmerParams = ShimmerParams(
        baseColor = MaterialTheme.colors.background,
        highlightColor = shimmerHighLight,
        durationMillis = 350,
        dropOff = 0.65f,
        tilt = 20f
      ),
 // shows an error text message when request failed.
 failure = {
   Text(text = "image request failed.")
 })

LocalCoilImageLoader

We can provide the same instance of the ImageLoader in the composable hierarchy.

val imageLoader = ImageLoader.Builder(context)
   // customize the ImageLoader as needed
   .build()
CompositionLocalProvider(LocalCoilImageLoader provides imageLoader) {
  // This will automatically use the value of current imageLoader in the hierarchy.
  CoilImage(
    imageModel = ...
  )
}

Coil Animated Image Support (GIF, Webp)

Landscapist-coil supports animated GIF and WebP Images using ImageLoader.

val context = LocalContext.current
val imageLoader = ImageLoader.Builder(context)
  .componentRegistry {
    if (SDK_INT >= 28) {
      add(ImageDecoderDecoder(context))
    } else {
      add(GifDecoder())
    }
  }
  .build()

CoilImage(
    imageModel = poster.gif, // URL of the animated images.
    imageLoader = imageLoader,
    shimmerParams = ShimmerParams(
      baseColor = background800,
      highlightColor = shimmerHighLight
    ),
    modifier = Modifier
      .fillMaxWidth()
      .padding(8.dp)
      .height(500.dp)
      .clip(RoundedCornerShape(8.dp))
  )
Fresco

Fresco

Maven Central
Add a dependency code to your module's build.gradle file.

" } ">
dependencies {
    implementation "com.github.skydoves:landscapist-fresco:
   
    "
   
}

Initialize

We should initialize Fresco using ImagePipelineConfig in our Application class.
If we need to fetch images from the network, recommend using OkHttpImagePipelineConfigFactory.
By using an ImagePipelineConfig, we can customize caching, networking, and thread pool strategies.
Here are more references related to the pipeline config.

class App : Application() {

  override fun onCreate() {
    super.onCreate()

    val pipelineConfig =
      OkHttpImagePipelineConfigFactory
        .newBuilder(this, OkHttpClient.Builder().build())
        .setDiskCacheEnabled(true)
        .setDownsampleEnabled(true)
        .setResizeAndRotateEnabledForNetwork(true)
        .build()

    Fresco.initialize(this, pipelineConfig)
  }
}

Usage

We can request and load images simply using a FrescoImage composable function.

FrescoImage(
  imageUrl = stringImageUrl,
  // Crop, Fit, Inside, FillHeight, FillWidth, None
  contentScale = ContentScale.Crop,
  // shows an image with a circular revealed animation.
  circularReveal = CircularReveal(duration = 250),
  // shows a placeholder ImageBitmap when loading.
  placeHolder = ImageBitmap.imageResource(R.drawable.placeholder),
  // shows an error ImageBitmap when the request failed.
  error = ImageBitmap.imageResource(R.drawable.error)
)

We can customize our requests using an ImageRequest that consists only of a URI, we can use the helper method ImageRequest.fromURI.

val imageRequest = ImageRequestBuilder
  .newBuilderWithSource(uri)
  .setImageDecodeOptions(decodeOptions)
  .setLocalThumbnailPreviewsEnabled(true)
  .setLowestPermittedRequestLevel(RequestLevel.FULL_FETCH)
  .setProgressiveRenderingEnabled(false)
  .setResizeOptions(ResizeOptions(width, height))
  .build()

FrescoImage(
  imageUrl = stringImageUrl,
  imageRequest = imageRequest,
  contentScale = ContentScale.Crop)

Composable loading, success, failure

We can create our own composable functions following requesting states.
Here is an example that shows a progress indicator when loading an image,
After complete requesting, the indicator will be gone and a content image will be shown.
If the request failed (e.g. network error, wrong destination), error text will be shown.

 FrescoImage(
 imageUrl = stringImageUrl,
 modifier = modifier,
 // shows a progress indicator when loading an image.
 loading = {
   ConstraintLayout(
     modifier = Modifier.fillMaxSize()
   ) {
     val indicator = createRef()
     CircularProgressIndicator(
       modifier = Modifier.constrainAs(indicator) {
         top.linkTo(parent.top)
         bottom.linkTo(parent.bottom)
        start.linkTo(parent.start)
        end.linkTo(parent.end)
       }
     )
   }
 },
 // shows an error text message when request failed.
 failure = {
   Text(text = "image request failed.")
 })

Also, we can customize the content image using our own composable function like below.

FrescoImage(
    imageUrl = imageUrl,
    // draw a resized image.
    success = { frescoImageState ->
      frescoImageState.imageBitmap?.let {
        Image(
          bitmap = it,
          modifier = Modifier
            .width(128.dp)
            .height(128.dp))
      }
    },
    loading = { 
      // do something 
    })

LocalFrescoImageRequest

We can provide the same instance of the ImageRequest in the composable hierarchy.

// customize the ImageRequest as needed
val imageRequest = ImageRequestBuilder
  .newBuilderWithSource(uri)
  .setImageDecodeOptions(decodeOptions)
  .setLocalThumbnailPreviewsEnabled(true)
  .setLowestPermittedRequestLevel(RequestLevel.FULL_FETCH)
  .setProgressiveRenderingEnabled(false)
  .setResizeOptions(ResizeOptions(width, height))
  .build()

CompositionLocalProvider(LocalFrescoImageRequest provides imageRequest) {
  // This will automatically use the value of current ImageRequest in the hierarchy.
  FrescoImage(
    imageurl = ...
  )
}

Palette

We can extract major (theme) color profiles using BitmapPalette. Basically, we should use BitmapPalette for extracting the major colors from image. You can reference which kinds of colors can be extracted here.

var palette by remember { mutableStateOf<Palette?>(null) }

GlideImage( // CoilImage, FrescoImage also can be used.
  imageModel = poster?.poster!!,
  bitmapPalette = BitmapPalette {
    palette = it
  }
)

Crossfade(
  targetState = palette,
  modifier = Modifier
    .padding(horizontal = 8.dp)
    .size(45.dp)
) {
  Box(
    modifier = Modifier
      .background(color = Color(it?.lightVibrantSwatch?.rgb ?: 0))
      .fillMaxSize()
  )
}

Also we can customize attributes of BitmapPalette like the below.

  var palette by remember { mutableStateOf<Palette?>(null) }

  GlideImage(
    imageModel = poster?.poster!!,
    modifier = Modifier
      .aspectRatio(0.8f),
    bitmapPalette = BitmapPalette(
      imageModel = poster.poster,
      useCache = true,
      interceptor = {
        it.addFilter { rgb, hsl ->
          // here edit to add the filter colors.
          false
        }
      },
      paletteLoadedListener = {
        palette = it
      }
    )
  )

Fresco Animated Image Support (GIF, Webp)

Maven Central
Add a dependency code to your module's build.gradle file.

" } ">
dependencies {
  implementation "com.github.skydoves:landscapist-fresco-websupport:
   
    "
   
}

Fresco supports animated GIF and WebP Images using FrescoWebImage composable function. We should pass the AbstractDraweeController that can be created like the below. You can reference how to build the DraweeController, and Supported URIs for setting URI addresses. Also, we can load a normal image (jpeg, png, etc) using the custom controller.

FrescoWebImage(
  controllerBuilder = Fresco.newDraweeControllerBuilder()
    .setUri(poster.gif) // GIF or Webp image url.
    .setAutoPlayAnimations(true),
  modifier = Modifier
    .fillMaxWidth()
    .height(300.dp)
)

Who's using Landscapist?

If your project uses Landscapist, let me know via creating a new issue! 🤗

Twitter for Android

twitter

Reference repository

This library is mostly inspired by Accompanist.

Accompanist is a group of libraries that contains some utilities which I've found myself copying around projects which use Jetpack Compose. Currently, it contains image loading and insets. You can get more variety and recent systems from the library maintained by Google.

Find this repository useful? ❤️

Support it by joining stargazers for this repository.
Also follow me for my next creations! 🤩

License

Designed and developed by 2020 skydoves (Jaewoong Eum)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Comments
  • Problem in preview

    Problem in preview

    Lib Version : implementation "com.github.skydoves:landscapist-glide:1.3.9"

    Testing Demo Code :

    GlideImage(
            imageModel = R.drawable.ic_launcher_background,
            contentScale = ContentScale.Crop,
            modifier = Modifier.aspectRatio(1f),
            loading = {
                ConstraintLayout(modifier = Modifier.fillMaxSize()) {
                    val indicator = createRef()
                    CircularProgressIndicator(
                        modifier = Modifier
                            .aspectRatio(1f)
                            .constrainAs(indicator) {
                                top.linkTo(parent.top)
                                bottom.linkTo(parent.bottom)
                                start.linkTo(parent.start)
                                end.linkTo(parent.end)
                            }
                            .defaultMinSize(128.dp)
                    )
                }
            },
            failure = {
                Text(text = "load failed!", )
            })
    

    Error : Render Problem in Design

    java.lang.IllegalStateException: You cannot call Glide.get() in registerComponents(), use the provided Glide instance instead   at com.bumptech.glide.Glide.checkAndInitializeGlide(Glide.java:205)   at com.bumptech.glide.Glide.get(Glide.java:191)   at com.bumptech.glide.Glide.getRetriever(Glide.java:774)   at com.bumptech.glide.Glide.with(Glide.java:801)   at com.skydoves.landscapist.glide.LocalGlideProvider.getGlideRequestManager(LocalGlideProvider.kt:75)   at com.skydoves.landscapist.glide.LocalGlideProvider.getGlideRequestBuilder(LocalGlideProvider.kt:63)   at com.skydoves.landscapist.glide.GlideImage__GlideImageKt.GlideImage(GlideImage.kt:369)   at com.skydoves.landscapist.glide.GlideImage.GlideImage(GlideImage.kt:1)   at com.ist.jetpackcompose.views.ComposeImageKt.GlideImageLoaderRounded(ComposeImage.kt:90)   at com.ist.jetpackcompose.ui.screen.list.GridActivityKt$GridItem$2.invoke(GridActivity.kt:123)   at com.ist.jetpackcompose.ui.screen.list.GridActivityKt$GridItem$2.invoke(GridActivity.kt:121)   at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)   at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)   at androidx.compose.material.SurfaceKt$Surface$6.invoke(Surface.kt:267)   at androidx.compose.material.SurfaceKt$Surface$6.invoke(Surface.kt:254)   at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)   at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)   at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:215)   at androidx.compose.material.SurfaceKt.Surface-F-jzlyU(Surface.kt:251)   at androidx.compose.material.SurfaceKt.Surface-9VG74zQ(Surface.kt:214)   at androidx.compose.material.CardKt.Card-9VG74zQ(Card.kt:126)   at com.ist.jetpackcompose.ui.screen.list.GridActivityKt.GridItem(GridActivity.kt:111)   at com.ist.jetpackcompose.ui.screen.list.GridActivityKt$GridActivityPreview$1$1$2$1$invoke$$inlined$items$1.invoke(LazyGrid.kt:240)   at com.ist.jetpackcompose.ui.screen.list.GridActivityKt$GridActivityPreview$1$1$2$1$invoke$$inlined$items$1.invoke(LazyGrid.kt:135)   at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:135)   at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)   at androidx.compose.foundation.lazy.LazyGridScopeImpl$items$1$1.invoke(LazyGrid.kt:235)   at androidx.compose.foundation.lazy.LazyGridScopeImpl$items$1$1.invoke(LazyGrid.kt:235)   at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)   at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)   at androidx.compose.foundation.lazy.LazyGridKt$FixedLazyGrid$1$1.invoke(LazyGrid.kt:205)   at androidx.compose.foundation.lazy.LazyGridKt$FixedLazyGrid$1$1.invoke(LazyGrid.kt:196)   at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:135)   at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)   at androidx.compose.foundation.lazy.LazyListScopeImpl$items$1$1.invoke(LazyDsl.kt:200)   at androidx.compose.foundation.lazy.LazyListScopeImpl$items$1$1.invoke(LazyDsl.kt:200)   at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)   at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)   at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:215)   at androidx.compose.runtime.saveable.SaveableStateHolderImpl.SaveableStateProvider(SaveableStateHolder.kt:84)   at androidx.compose.foundation.lazy.LazyListItemContentFactory$CachedItemContent$content$1.invoke(LazyListItemContentFactory.kt:113)   at androidx.compose.foundation.lazy.LazyListItemContentFactory$CachedItemContent$content$1.invoke(LazyListItemContentFactory.kt:107)   at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)   at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)   at androidx.compose.ui.layout.SubcomposeLayoutState$subcompose$2$1$1.invoke(SubcomposeLayout.kt:241)   at androidx.compose.ui.layout.SubcomposeLayoutState$subcompose$2$1$1.invoke(SubcomposeLayout.kt:241)   at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)   at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)   at androidx.compose.runtime.ComposerKt.invokeComposable(Composer.kt:3332)   at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:2577)   at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:2566)   at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(SnapshotState.kt:540)   at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:2566)   at androidx.compose.runtime.ComposerImpl.composeContent$runtime_release(Composer.kt:2517)   at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:477)   at androidx.compose.runtime.Recomposer.composeInitial$runtime_release(Recomposer.kt:727)   at androidx.compose.runtime.ComposerImpl$CompositionContextImpl.composeInitial$runtime_release(Composer.kt:2982)   at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:433)   at androidx.compose.ui.layout.SubcomposeLayoutState.subcomposeInto(SubcomposeLayout.kt:259)   at androidx.compose.ui.layout.SubcomposeLayoutState.access$subcomposeInto(SubcomposeLayout.kt:145)   at androidx.compose.ui.layout.SubcomposeLayoutState$subcompose$2.invoke(SubcomposeLayout.kt:234)   at androidx.compose.ui.layout.SubcomposeLayoutState$subcompose$2.invoke(SubcomposeLayout.kt:231)   at androidx.compose.runtime.snapshots.SnapshotStateObserver.withNoObservations(SnapshotStateObserver.kt:144)   at androidx.compose.ui.node.OwnerSnapshotObserver.withNoSnapshotReadObservation$ui_release(OwnerSnapshotObserver.kt:49)   at androidx.compose.ui.node.LayoutNode.withNoSnapshotReadObservation$ui_release(LayoutNode.kt:1107)   at androidx.compose.ui.layout.SubcomposeLayoutState.subcompose(SubcomposeLayout.kt:231)   at androidx.compose.ui.layout.SubcomposeLayoutState.subcompose(SubcomposeLayout.kt:226)   at androidx.compose.ui.layout.SubcomposeLayoutState.subcompose$ui_release(SubcomposeLayout.kt:215)   at androidx.compose.ui.layout.SubcomposeLayoutState$Scope.subcompose(SubcomposeLayout.kt:466)   at androidx.compose.foundation.lazy.LazyMeasuredItemProvider.getAndMeasure-ZjPyQlc(LazyMeasuredItemProvider.kt:48)   at androidx.compose.foundation.lazy.LazyListMeasureKt.measureLazyList-9CW8viI(LazyListMeasure.kt:145)   at androidx.compose.foundation.lazy.LazyListKt$LazyList$1.invoke-0kLqBqw(LazyList.kt:152)   at androidx.compose.foundation.lazy.LazyListKt$LazyList$1.invoke(LazyList.kt:76)   at androidx.compose.ui.layout.SubcomposeLayoutState$createMeasurePolicy$1.measure-3p2s80s(SubcomposeLayout.kt:345)   at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0(InnerPlaceable.kt:43)   at androidx.compose.foundation.layout.PaddingValuesModifier.measure-3p2s80s(Padding.kt:417)   at androidx.compose.ui.node.ModifiedLayoutNode.measure-BRTryo0(ModifiedLayoutNode.kt:39)   at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:219)   at androidx.compose.ui.node.ModifiedLayoutNode.measure-BRTryo0(ModifiedLayoutNode.kt:39)   at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:116)   at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:116)   at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:116)   at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$3.invoke(OuterMeasurablePlaceable.kt:100)   at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$3.invoke(OuterMeasurablePlaceable.kt:99)   at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:128)   at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:75)   at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:63)   at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0(OuterMeasurablePlaceable.kt:99)   at androidx.compose.ui.node.OuterMeasurablePlaceable.measure-BRTryo0(OuterMeasurablePlaceable.kt:71)   at androidx.compose.ui.node.LayoutNode.measure-BRTryo0(LayoutNode.kt:1227)   at androidx.compose.foundation.layout.RowColumnImplKt$rowColumnMeasurePolicy$1.measure-3p2s80s(RowColumnImpl.kt:89)   at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0(InnerPlaceable.kt:43)   at androidx.compose.foundation.layout.FillModifier.measure-3p2s80s(Size.kt:627)   at androidx.compose.ui.node.ModifiedLayoutNode.measure-BRTryo0(ModifiedLayoutNode.kt:39)   at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$3.invoke(OuterMeasurablePlaceable.kt:100)   at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$3.invoke(OuterMeasurablePlaceable.kt:99)   at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:128)   at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:75)   at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:63)   at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0(OuterMeasurablePlaceable.kt:99)   at androidx.compose.ui.node.OuterMeasurablePlaceable.measure-BRTryo0(OuterMeasurablePlaceable.kt:71)   at androidx.compose.ui.node.LayoutNode.measure-BRTryo0(LayoutNode.kt:1227)   at androidx.compose.foundation.layout.RowColumnImplKt$rowColumnMeasurePolicy$1.measure-3p2s80s(RowColumnImpl.kt:89)   at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0(InnerPlaceable.kt:43)   at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$3.invoke(OuterMeasurablePlaceable.kt:100)   at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$3.invoke(OuterMeasurablePlaceable.kt:99)   at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:128)   at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:75)   at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:63)   at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0(OuterMeasurablePlaceable.kt:99)   at androidx.compose.ui.node.OuterMeasurablePlaceable.measure-BRTryo0(OuterMeasurablePlaceable.kt:71)   at androidx.compose.ui.node.LayoutNode.measure-BRTryo0(LayoutNode.kt:1227)   at androidx.compose.ui.layout.RootMeasurePolicy.measure-3p2s80s(RootMeasurePolicy.kt:38)   at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0(InnerPlaceable.kt:43)   at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:116)   at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:116)   at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:116)   at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$3.invoke(OuterMeasurablePlaceable.kt:100)   at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$3.invoke(OuterMeasurablePlaceable.kt:99)   at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:1776)   at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:123)   at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:75)   at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:63)   at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0(OuterMeasurablePlaceable.kt:99)   at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release(LayoutNode.kt:1236)   at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-0kLqBqw(MeasureAndLayoutDelegate.kt:169)   at androidx.compose.ui.node.MeasureAndLayoutDelegate.access$doRemeasure-0kLqBqw(MeasureAndLayoutDelegate.kt:38)   at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureAndLayout(MeasureAndLayoutDelegate.kt:207)   at androidx.compose.ui.platform.AndroidComposeView.onMeasure_Original(AndroidComposeView.android.kt:547)   at androidx.compose.ui.platform.AndroidComposeView.onMeasure(AndroidComposeView.android.kt:-1)   at android.view.View.measure_Original(View.java:25466)   at android.view.View_Delegate.measure(View_Delegate.java:80)   at android.view.View.measure(View.java:25430)   at androidx.compose.ui.platform.AbstractComposeView.internalOnMeasure$ui_release(ComposeView.android.kt:278)   at androidx.compose.ui.platform.AbstractComposeView.onMeasure_Original(ComposeView.android.kt:265)   at androidx.compose.ui.platform.AbstractComposeView.onMeasure(ComposeView.android.kt:-1)   at android.view.View.measure_Original(View.java:25466)   at android.view.View_Delegate.measure(View_Delegate.java:80)   at android.view.View.measure(View.java:25430)   at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6957)   at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)   at android.view.View.measure_Original(View.java:25466)   at android.view.View_Delegate.measure(View_Delegate.java:80)   at android.view.View.measure(View.java:25430)   at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6957)   at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)   at android.view.View.measure_Original(View.java:25466)   at android.view.View_Delegate.measure(View_Delegate.java:80)   at android.view.View.measure(View.java:25430)   at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:735)   at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:481)   at android.view.View.measure_Original(View.java:25466)   at android.view.View_Delegate.measure(View_Delegate.java:80)   at android.view.View.measure(View.java:25430)   at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6957)   at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)   at android.view.View.measure_Original(View.java:25466)   at android.view.View_Delegate.measure(View_Delegate.java:80)   at android.view.View.measure(View.java:25430)

    opened by imandaliya 18
  • Height issue with ContentScale.FillWidth

    Height issue with ContentScale.FillWidth

    • Library Version: landscapist-coil:1.5.2
    • Affected Device: Emulator Android 10, Samsung devices Android 11/12

    Describe the Bug:

    I wanted to add rounded corners to images that I'm loading, their contentScale is set to ContentScale.FillWidth, so I'm expecting that once the image is loaded the bounds are updated and the clip() modifier is applied. I added a border so the issue can be visible.

    HorizontalPager(
                count = content.size,
                state = pagerState,
                modifier = Modifier.fillMaxHeight(fraction = 0.67f),
                verticalAlignment = Alignment.CenterVertically,
                contentPadding = PaddingValues(horizontal = 23.dp)
            ) { page ->
                content.getOrNull(page)?.let {
                    CoilImage(
                        imageModel = it.location,
                        contentDescription = it.fileName,
                        contentScale = ContentScale.FillWidth,
                        // FIXME: 24.05.22 found a solution for rounded corners.
                        modifier = Modifier
                            .padding(horizontal = 7.dp)
                            .fillMaxWidth()
                            .clip(
                                RoundedCornerShape(16.dp)
                            )
                            .border(0.5.dp, color = grayscale20, shape = RoundedCornerShape(16.dp))
                    )
            }
    }
    
    Screenshot 2022-05-25 at 10 28 29

    Expected Behavior:

    This actually works if I use Coil 2.0 directly

    HorizontalPager(
                count = content.size,
                state = pagerState,
                modifier = Modifier.fillMaxHeight(fraction = 0.67f),
                verticalAlignment = Alignment.CenterVertically,
                contentPadding = PaddingValues(horizontal = 23.dp)
            ) { page ->
                content.getOrNull(page)?.let {
                    AsyncImage(
                        model = it.location,
                        contentDescription = it.fileName,
                        contentScale = ContentScale.FillWidth,
                        modifier = Modifier
                            .padding(horizontal = 7.dp)
                            .fillMaxWidth()
                            .clip(
                                RoundedCornerShape(16.dp)
                            )
                            .border(0.5.dp, color = grayscale20, shape = RoundedCornerShape(16.dp))
                    )
                }
            }
    
    Screenshot 2022-05-25 at 10 33 59
    opened by luiscurini 14
  • Shimmer effect is not working for GlideImage

    Shimmer effect is not working for GlideImage

    • Library Version 1.3.2

    • Affected Device(s) [e.g. Samsung Galaxy s10 with Android 9.0] Android Emulator version API 30

    Describe the Bug: Shimmer Effect is not working for GlideImage

    GlideImage(
            modifier = modifier,
            contentScale = contentScale,
            imageModel = someImageUrl,
            shimmerParams = ShimmerParams(
                        baseColor = Color.White,
                        highlightColor = Color.Black,
                        durationMillis = 350,
                        dropOff = 0.65f,
                        tilt = 20f
              )
        )
    

    This example doesn't show any shimmer effect :( Looks like is not working.

    Expected Behavior: It should show shimmer effect while loading the image.

    opened by atonamy 8
  • FrescoImage crashing with Compose beta 07

    FrescoImage crashing with Compose beta 07

    Please complete the following information:

    • Library Version [v1.2.1]
    • Affected Device(s) [e.g. Pixel 4 XL]

    Describe the Bug:

    After updating the compose dependency to 1.0.0-beta07, FrescoImage usages crash at runtime with this stacktrace:

    05-19 10:09:28.796 29352 29352 E AndroidRuntime: FATAL EXCEPTION: main
    05-19 10:09:28.796 29352 29352 E AndroidRuntime: Process: com.twitter.sandbox.uiarch, PID: 29352
    05-19 10:09:28.796 29352 29352 E AndroidRuntime: java.lang.NoSuchMethodError: No interface method startRestartGroup(ILjava/lang/String;)Landroidx/compose/runtime/Composer; in class Landroidx/compose/runtime/Composer; or its super classes (declaration of 'androidx.compose.runtime.Composer' appears in /data/app/~~xzvvhkZTNhoZWKRPq8VHJg==/com.twitter.sandbox.uiarch-W3sSHxog8MH9aWO23m7A6A==/base.apk)
    05-19 10:09:28.796 29352 29352 E AndroidRuntime: 	at com.skydoves.landscapist.fresco.FrescoImage__FrescoImageKt.FrescoImage(FrescoImage.kt:85)
    05-19 10:09:28.796 29352 29352 E AndroidRuntime: 	at com.skydoves.landscapist.fresco.FrescoImage.FrescoImage(FrescoImage.kt:1)
    05-19 10:09:28.796 29352 29352 E AndroidRuntime: 	at com.twitter.sandbox.uiarch.samples.dogs.DogContentViewProviderKt.ShowDog(DogContentViewProvider.kt:136)
    

    And this is the calling code:

        Row(modifier = Modifier.clickable { viewModel.loadNewDog() }) {
            FrescoImage(imageUrl = dogImage.url, modifier = Modifier.fillMaxSize(), contentScale = ContentScale.Fit)
        }
    

    Expected Behavior:

    Using FrescoImage should not cause a runtime crash.

    opened by mrmans0n 8
  • FrescoImage crashes in LazyRow/LazyColumn due to java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap

    FrescoImage crashes in LazyRow/LazyColumn due to java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap

    Please complete the following information:

    • Library Version [1.2.4]
    • Affected Device(s) [Pixel 4 XL, Emulators]

    Describe the Bug:

    When using FrescoImage in LazyRow / LazyColumn (any LazyItemScope based layout), for any amount of items that is more than the ones that fit on screen (so that there can be recycling happening), if you scroll around it will eventually crash due to trying to use a recycled Bitmap. It is 100% reproducible if you scroll around your list of FrescoImage items and also background/foreground the app a bunch of times. Sometimes it's fast to crash, sometimes it takes a couple of tries.

    Attached video with my repro steps:

    https://user-images.githubusercontent.com/534307/123402571-29f3d600-d5a8-11eb-98b4-b6e6ca13e686.mp4

    Code:

    LazyRow {
            item {
                Box(modifier = Modifier.padding(
                    start = 16.dp,
                    bottom = 16.dp,
                    top = 16.dp,
                    end = 8.dp
                )) {
                    Icon(
                        imageVector = Icons.Filled.Favorite,
                        contentDescription = "Favorite",
                        modifier = Modifier.size(50.dp),
                        tint = Color.Red
                    )
                }
            }
            items(dogs) { favorite ->
                Card(modifier = Modifier.padding(horizontal = 8.dp, vertical = 16.dp)) {
                    FrescoImage(
                        imageUrl = favorite.image.url,
                        modifier = Modifier.size(50.dp),
                        contentScale = ContentScale.Crop
                    )
                }
            }
        }
    }
    

    Stacktrace:

    06-25 11:12:10.063 24136 24136 E AndroidRuntime: java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@95343df
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at android.graphics.BaseCanvas.throwIfCannotDraw(BaseCanvas.java:66)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at android.graphics.RecordingCanvas.throwIfCannotDraw(RecordingCanvas.java:277)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at android.graphics.BaseRecordingCanvas.drawBitmap(BaseRecordingCanvas.java:88)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.graphics.AndroidCanvas.drawImageRect-HPBpro0(AndroidCanvas.android.kt:275)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.graphics.drawscope.CanvasDrawScope.drawImage-9jGpkUE(CanvasDrawScope.kt:227)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeDrawScope.drawImage-9jGpkUE(Unknown Source:37)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.graphics.drawscope.DrawScope$DefaultImpls.drawImage-9jGpkUE$default(DrawScope.kt:459)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.graphics.painter.BitmapPainter.onDraw(BitmapPainter.kt:55)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.graphics.painter.Painter.draw-x_KDEd0(Painter.kt:212)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.draw.PainterModifier.draw(PainterModifier.kt:289)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.ModifiedDrawNode.performDraw(ModifiedDrawNode.kt:102)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:243)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:98)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:254)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:253)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:124)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:75)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:253)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:53)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.platform.RenderNodeApi29.record(RenderNodeApi29.android.kt:156)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.platform.RenderNodeLayer.updateDisplayList(RenderNodeLayer.android.kt:243)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.platform.RenderNodeLayer.drawLayer(RenderNodeLayer.android.kt:224)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:238)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:98)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:243)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:98)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:243)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:98)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:243)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNode.draw$ui_release(LayoutNode.kt:805)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:104)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:243)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:98)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:243)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:98)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:243)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:98)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:243)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:98)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:243)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNode.draw$ui_release(LayoutNode.kt:805)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:104)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:243)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.performDraw(DelegatingLayoutNodeWrapper.kt:67)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:243)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.performDraw(DelegatingLayoutNodeWrapper.kt:67)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:254)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:253)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:124)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:75)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:253)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:53)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.platform.RenderNodeApi29.record(RenderNodeApi29.android.kt:156)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.platform.RenderNodeLayer.updateDisplayList(RenderNodeLayer.android.kt:243)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.platform.RenderNodeLayer.drawLayer(RenderNodeLayer.android.kt:224)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:238)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:98)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:243)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeDrawScope.drawContent(LayoutNodeDrawScope.kt:42)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.foundation.Background.draw(Background.kt:107)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.ModifiedDrawNode.performDraw(ModifiedDrawNode.kt:102)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:254)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:253)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:124)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:75)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:253)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:53)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.platform.RenderNodeApi29.record(RenderNodeApi29.android.kt:156)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.platform.RenderNodeLayer.updateDisplayList(RenderNodeLayer.android.kt:243)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.platform.RenderNodeLayer.drawLayer(RenderNodeLayer.android.kt:224)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:238)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:98)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:243)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:98)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:254)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:253)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:124)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:75)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:253)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:53)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.platform.RenderNodeApi29.record(RenderNodeApi29.android.kt:156)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.platform.RenderNodeLayer.updateDisplayList(RenderNodeLayer.android.kt:243)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.platform.RenderNodeLayer.drawLayer(RenderNodeLayer.android.kt:224)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:238)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNode.draw$ui_release(LayoutNode.kt:805)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:104)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:243)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:98)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:254)
    06-25 11:12:10.063 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:253)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:1788)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:119)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:75)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:253)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:53)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.platform.RenderNodeApi29.record(RenderNodeApi29.android.kt:156)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.platform.RenderNodeLayer.updateDisplayList(RenderNodeLayer.android.kt:243)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at androidx.compose.ui.platform.AndroidComposeView.dispatchDraw(AndroidComposeView.android.kt:674)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.View.draw(View.java:22353)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.View.updateDisplayListIfDirty(View.java:21226)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4500)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4473)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.View.updateDisplayListIfDirty(View.java:21186)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4500)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4473)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.View.updateDisplayListIfDirty(View.java:21186)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4500)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4473)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.View.updateDisplayListIfDirty(View.java:21186)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4500)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4473)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.View.updateDisplayListIfDirty(View.java:21186)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4500)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4473)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.View.updateDisplayListIfDirty(View.java:21186)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4500)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4473)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.View.updateDisplayListIfDirty(View.java:21186)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:559)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:565)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:642)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ViewRootImpl.draw(ViewRootImpl.java:4106)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:3833)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3104)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1948)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8177)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:972)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.Choreographer.doCallbacks(Choreographer.java:796)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.Choreographer.doFrame(Choreographer.java:731)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.os.Handler.handleCallback(Handler.java:938)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.os.Handler.dispatchMessage(Handler.java:99)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.os.Looper.loop(Looper.java:223)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at android.app.ActivityThread.main(ActivityThread.java:7664)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at java.lang.reflect.Method.invoke(Native Method)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
    06-25 11:12:10.064 24136 24136 E AndroidRuntime: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
    

    Expected Behavior:

    No crashes when recycling items.

    opened by mrmans0n 7
  • [Glide] Add Gif support with GlideImage

    [Glide] Add Gif support with GlideImage

    The LocalGlideProvider only supports Drawable?:

    public val LocalGlideRequestBuilder: ProvidableCompositionLocal<RequestBuilder<Drawable>?> =
      staticCompositionLocalOf { null }
    

    By changing this to support GifDrawable?, we can support Glide's .asGif():

    
    /**
     * Local containing the preferred [RequestOptions] for providing the same instance
     * in our composable hierarchy.
     */
    public val LocalGlideGifRequestOptions: ProvidableCompositionLocal<RequestOptions?> =
      staticCompositionLocalOf { null }
    
    /**
     * Local containing the preferred [RequestBuilder] for providing the same instance
     * in our composable hierarchy.staticCompositionLocalOf
     */
    public val LocalGlideGifRequestBuilder: ProvidableCompositionLocal<RequestBuilder<GifDrawable>?> =
      staticCompositionLocalOf { null }
    
    /**
     * Local containing the preferred [RequestManager] for providing the same instance
     * in our composable hierarchy.staticCompositionLocalOf
     */
    public val LocalGlideGifRequestManager: ProvidableCompositionLocal<RequestManager?> =
      staticCompositionLocalOf { null }
    
    /** A provider for taking the local instances related to the `GlideImage`. */
    internal object LocalGlideGifProvider {
    
      /** Returns the current or default [RequestOptions] for the `GlideImage` parameter. */
      @Composable
      fun getGlideRequestOptions(): RequestOptions {
        return LocalGlideGifRequestOptions.current ?: RequestOptions()
      }
    
      /** Returns the current or default [RequestBuilder] for the `GlideImage` parameter. */
      @Composable
      fun getGlideRequestBuilder(): RequestBuilder<GifDrawable> {
        return LocalGlideGifRequestBuilder.current
               ?: getGlideRequestManager()
                 .asGif()
      }
    
      /** Returns the current or default [RequestManager] for the `GlideImage` processor. */
      @Composable
      fun getGlideRequestManager(): RequestManager {
        // By default Glide tries to install lifecycle listeners to automatically re-trigger
        // requests when resumed. We don't want that with Compose, since we rely on composition
        // for our 'lifecycle'. We can stop Glide doing this by using the application context.
        return LocalGlideGifRequestManager.current
               ?: GlideApp.with(LocalContext.current.applicationContext)
      }
    }
    

    Can we provide a LocalGlideGifProvider, LocalGlideBitmapProvider and LocalGlideDrawableProvider providers?

    enhancement 
    opened by jaredsburrows 6
  • LazyVerticalGrid Fresco scroll crash

    LazyVerticalGrid Fresco scroll crash

    • Library Version com.github.skydoves:landscapist-fresco:1.5.2
    • Affected Device: Google Pixel 4a (Android 12)
    • Not Reproducable: Huawei P30 Pro (Android 11)
    • target & compile Sdk: 31
    • compose version: 1.2.0-beta02

    Describe the Bug:

    When using a LazyVerticalGrid with following minimal example, the app crashes upon scrolling, when using more than 30+ image Items. I can't reproduce the crash with my Huawei P30 Pro which runs Android 11, so it could also be a Android 12 kind of problem. But even when I test on my Huawei P30 Pro device, the pictures, which are really not that big, are loaded very slowly.

    @Composable
    fun GalleryScreen(navController: NavController, imageUrls: List<String>?) {
        if (i == null) return
    
        LazyVerticalGrid(
            columns = GridCells.Fixed(3)) {
            items(imageUrls) { imageUrl ->
                Box(modifier = Modifier.aspectRatio(1f)) {
                    FrescoImage(
                        imageUrl = imageUrl,
                        contentScale = ContentScale.Crop
                    )
                }
            }
        }
    }
    

    Error message is:

    E/AndroidRuntime: FATAL EXCEPTION: main
        Process: app.festiguide, PID: 7549
        java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@8a09c7c
            at android.graphics.BaseCanvas.throwIfCannotDraw(BaseCanvas.java:74)
            at android.graphics.RecordingCanvas.throwIfCannotDraw(RecordingCanvas.java:263)
            at android.graphics.BaseRecordingCanvas.drawBitmap(BaseRecordingCanvas.java:94)
            at androidx.compose.ui.graphics.AndroidCanvas.drawImageRect-HPBpro0(AndroidCanvas.android.kt:271)
            at androidx.compose.ui.graphics.drawscope.CanvasDrawScope.drawImage-AZ2fEMs(CanvasDrawScope.kt:263)
            at androidx.compose.ui.node.LayoutNodeDrawScope.drawImage-AZ2fEMs(Unknown Source:39)
            at androidx.compose.ui.graphics.drawscope.DrawScope$DefaultImpls.drawImage-AZ2fEMs$default(DrawScope.kt:508)
            at androidx.compose.ui.graphics.painter.BitmapPainter.onDraw(BitmapPainter.kt:93)
            at androidx.compose.ui.graphics.painter.Painter.draw-x_KDEd0(Painter.kt:212)
            at androidx.compose.ui.draw.PainterModifier.draw(PainterModifier.kt:281)
            at androidx.compose.ui.node.DrawEntity.draw(DrawEntity.kt:98)
            at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:316)
            at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:306)
            at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:139)
            at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:314)
            at androidx.compose.ui.node.LayoutNodeWrapper.access$drawContainedDrawModifiers(LayoutNodeWrapper.kt:60)
            at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:336)
            at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:335)
            at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2098)
            at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:112)
            at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:78)
            at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:335)
            at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:60)
            at androidx.compose.ui.platform.RenderNodeApi29.record(RenderNodeApi29.android.kt:180)
            at androidx.compose.ui.platform.RenderNodeLayer.updateDisplayList(RenderNodeLayer.android.kt:297)
            at androidx.compose.ui.platform.RenderNodeLayer.drawLayer(RenderNodeLayer.android.kt:238)
            at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:301)
            at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:139)
            at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:314)
            at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:306)
            at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:139)
            at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:314)
            at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:306)
            at androidx.compose.ui.node.LayoutNode.draw$ui_release(LayoutNode.kt:831)
            at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:90)
            at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:314)
            at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:306)
            at androidx.compose.ui.node.LayoutNode.draw$ui_release(LayoutNode.kt:831)
            at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:90)
            at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:314)
            at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:306)
            at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:139)
            at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:314)
            at androidx.compose.ui.node.LayoutNodeWrapper.access$drawContainedDrawModifiers(LayoutNodeWrapper.kt:60)
            at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:336)
            at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:335)
            at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2098)
            at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:112)
            at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:78)
            at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:335)
            at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:60)
            at androidx.compose.ui.platform.RenderNodeApi29.record(RenderNodeApi29.android.kt:180)
            at androidx.compose.ui.platform.RenderNodeLayer.updateDisplayList(RenderNodeLayer.android.kt:297)
            at androidx.compose.ui.platform.RenderNodeLayer.drawLayer(RenderNodeLayer.android.kt:238)
            at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:301)
            at androidx.compose.ui.node.LayoutNode.draw$ui_release(LayoutNode.kt:831)
            at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:90)
            at androidx.compose.ui.node.LayoutNodeDrawScope.drawContent(LayoutNodeDrawScope.kt:48)
            at androidx.compose.foundation.gestures.DrawOverScrollModifier.draw(AndroidOverScroll.kt:75)
            at androidx.compose.ui.node.DrawEntity.draw(DrawEntity.kt:98)
            at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:316)
            at androidx.compose.ui.node.LayoutNodeWrapper.access$drawContainedDrawModifiers(LayoutNodeWrapper.kt:60)
            at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:336)
            at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:335)
            at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2098)
            at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:112)
            at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:78)
            at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:335)
            at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:60)
            at androidx.compose.ui.platform.RenderNodeApi29.record(RenderNodeApi29.android.kt:180)
            at androidx.compose.ui.platform.RenderNodeLayer.updateDisplayList(RenderNodeLayer.android.kt:297)
            at androidx.compose.ui.platform.AndroidComposeView.dispatchDraw(AndroidComposeView.android.kt:948)
            at android.view.View.draw(View.java:22707)
            at android.view.View.updateDisplayListIfDirty(View.java:21579)
            at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4512)
            at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4485)
            at android.view.View.updateDisplayListIfDirty(View.java:21535)
            at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4512)
            at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4485)
            at android.view.View.updateDisplayListIfDirty(View.java:21535)
            at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4512)
            at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4485)
            at android.view.View.updateDisplayListIfDirty(View.java:21535)
            at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4512)
            at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4485)
            at android.view.View.updateDisplayListIfDirty(View.java:21535)
            at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:534)
            at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:540)
            at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:616)
            at android.view.ViewRootImpl.draw(ViewRootImpl.java:4525)
            at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:4245)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3374)
    E/AndroidRuntime:     at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2179)
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8787)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1037)
            at android.view.Choreographer.doCallbacks(Choreographer.java:845)
            at android.view.Choreographer.doFrame(Choreographer.java:780)
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1022)
            at android.os.Handler.handleCallback(Handler.java:938)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loopOnce(Looper.java:201)
            at android.os.Looper.loop(Looper.java:288)
            at android.app.ActivityThread.main(ActivityThread.java:7870)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
    

    To facilitate reproducing the error you can use the following images.

                listOf(
                    "https://live.staticflickr.com/65535/52140374025_d4f6fbbb61_z.jpg",
                    "https://live.staticflickr.com/65535/52115578994_31a9d3f9d4_z.jpg",
                    "https://live.staticflickr.com/65535/52115842270_a8083c1a31_z.jpg",
                    "https://live.staticflickr.com/65535/52115842105_2449d96d93_z.jpg",
                    "https://live.staticflickr.com/65535/52115578264_38a35faa82_z.jpg",
                    "https://live.staticflickr.com/65535/52115332496_e3be093187_z.jpg",
                    "https://live.staticflickr.com/65535/52114308052_7d47e89981_z.jpg",
                    "https://live.staticflickr.com/65535/52115840490_72571bbaa8_z.jpg",
                    "https://live.staticflickr.com/65535/52115840220_46a94fdb1a_z.jpg",
                    "https://live.staticflickr.com/65535/52115840005_385b248a30_z.jpg",
    
                    "https://live.staticflickr.com/65535/52115330526_72373e8750_z.jpg",
                    "https://live.staticflickr.com/65535/52115371733_d363ef5a9a_z.jpg",
                    "https://live.staticflickr.com/65535/52115839350_908cde3ac8_z.jpg",
                    "https://live.staticflickr.com/65535/52115373383_f0f534b1e3_z.jpg",
                    "https://live.staticflickr.com/65535/52115577404_0902caf6d4_z.jpg",
                    "https://live.staticflickr.com/65535/52115840715_8d77dbda48_z.jpg",
                    "https://live.staticflickr.com/65535/52114305022_8a55b5b037_z.jpg",
                    "https://live.staticflickr.com/65535/52114304832_2e322f70cd_z.jpg",
                    "https://live.staticflickr.com/65535/52115328916_59a10be33e_z.jpg",
                    "https://live.staticflickr.com/65535/52114304502_a397e38038_z.jpg",
    
                    "https://live.staticflickr.com/65535/52121460286_aa7cb20e1d_z.jpg",
                    "https://live.staticflickr.com/65535/52121490528_fbbb1e0aa6_z.jpg",
                    "https://live.staticflickr.com/65535/52121959385_ab62aecccb_z.jpg",
                    "https://live.staticflickr.com/65535/52121959350_871200e394_z.jpg",
                    "https://live.staticflickr.com/65535/52121705619_b0ea6ce267_z.jpg",
                    "https://live.staticflickr.com/65535/52121959265_d642b29314_z.jpg",
                    "https://live.staticflickr.com/65535/52121959205_75acaa67b0_z.jpg",
                    "https://live.staticflickr.com/65535/52121490263_a4d3ea603f_z.jpg",
                    "https://live.staticflickr.com/65535/52121490208_22d31dcba9_z.jpg",
                    "https://live.staticflickr.com/65535/52121459831_3baeb07703_z.jpg",
    
                    "https://live.staticflickr.com/65535/52121490113_d8e5c9a9b2_z.jpg",
                    "https://live.staticflickr.com/65535/52121958980_d8f5eaa067_z.jpg",
                    "https://live.staticflickr.com/65535/52121958945_c5818b15e2_z.jpg",
                    "https://live.staticflickr.com/65535/52121705284_6a8e5ceba1_z.jpg",
                    "https://live.staticflickr.com/65535/52121459606_2ebf4b9939_z.jpg",
                    "https://live.staticflickr.com/65535/52121958815_7466a5489d_z.jpg",
                    "https://live.staticflickr.com/65535/52121459501_c433bd01d6_z.jpg",
                    "https://live.staticflickr.com/65535/52120425527_c8b93f0e39_z.jpg",
                    "https://live.staticflickr.com/65535/52121958660_3c84e93a7c_z.jpg",
                    "https://live.staticflickr.com/65535/52120425482_dd4e5a234c_z.jpg",
                )
    
    

    Expected Behavior:

    When I use LazyColumn instead of LazyVerticalGrid everything works fine, so I expect a similar behavior just like when I use LazyColumn. Generally the photos are loaded much slower within a LazyVerticalGrid than in a LazyColumn.

        LazyColumn {
            items(imageUrls.value) { imageUrl ->
                Box(modifier = Modifier.aspectRatio(1f)) {
                    FrescoImage(
                        imageUrl = imageUrl,
                        contentScale = ContentScale.Crop,
                        placeHolder = ImageBitmap.imageResource(R.drawable.img_placeholder_gallery)
                    )
                }
            }
        }
    

    I hope you can understand and reproduce my problem. If you need any more information, just ask.

    opened by andreas-umbricht 5
  • Images not recomposing after changing the list of a LazyList

    Images not recomposing after changing the list of a LazyList

    Please complete the following information:

    • Glide and Fresco v1.2.4

    Describe the Bug:

    I'm observing a Live Data List using observeAsState(). When I trigger a new event using value/postDelayed, the LazyList (LazyRow/LazyColumn) item recomposes everything (text, icons, colors) except the Glide/Fresco image, making the item keep the old image URL. I'm attaching a small video, you can see that when I remove an item for the list, the title and rating updates, but the image doesn't. This doesn't happen if I use the classic Accompanist Glide library. WhatsApp Video 2021-06-21 at 22.41.zip

    Expected Behavior:

    Whenever the list state changes, the image should recompose too.

    Current Glide Code:

    >@Composable
    > fun PosterImage(posterURL:String){
    >     GlideImage(
    >                 imageModel = posterURL,
    >                 contentScale = ContentScale.FillWidth,
    >                 circularRevealedEnabled = true,
    >                 placeHolder = ImageBitmap.imageResource(R.drawable.entry_placeholder),
    >                 alignment = Alignment.Center,
    >                 modifier = Modifier
    >                     .fillMaxWidth()
    >                     .height(170.dp),
    >                 requestOptions = RequestOptions().diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
    >             )
    > }
    
    bug 
    opened by davidsal 5
  • Images not loading after started using compose 1.0.0-alpha08

    Images not loading after started using compose 1.0.0-alpha08

    • Library Version: v1.1.1
    • Pixel 4, Emulator

    Images not loading anymore after started to use compose 1.0.0-alpha08, i have a CircularProgressIndicator set for loading {} only that one is shown. No actual is loaded from provided url

    Expected Behavior:

    Images can be loaded

    opened by miduch 5
  • Blur effect on image  | applying transformation on glide view

    Blur effect on image | applying transformation on glide view

    Is your feature request related to a problem? I have the requirement of showing different loading/error/success state in my composable. I also need to apply blur effect (right now just this, for other people it could be some other effect ) for success image.

    Describe the solution you'd like:

    I am not sure if there is already support of such in landscapist.

    If yes, then could u please help to know how it could be done. if no, If feasible and worthwhile your time, please see what can be done here.

    Describe alternatives you've considered: There is something like this which seems to be working. https://stackoverflow.com/a/47262444/14034095

    How do we apply transformation to GlideImage or such. Glide.with(context) .load(“YOUR IMAGE URL HERE”) .bitmapTransform(new BlurTransformation(context)) .into(imageView);

    p.s. This is an awesome library, really helped me a lot. Thanks for this.

    opened by RishiKrYML 4
  • Avoid excessive network requests when image fails to load

    Avoid excessive network requests when image fails to load

    We have a case where we may get a bad URL as input, and the image will fail to load. In this case, upon every recomposition GlideImage will try to reload the failing image. This is a lot of unnecessary network usage and churn.

    Any ideas how to make it stop trying to load after the first failure? It doesn't look like Glide itself has this feature (maximum retries, for instance).

    Thanks!

    opened by kurteous 4
Releases(2.1.0)
  • 2.1.0(Nov 12, 2022)

    What's Changed

    • Bump Compose to 1.3.1 by @skydoves in https://github.com/skydoves/landscapist/pull/196
    • Introduce landscapist-bom module by @skydoves in https://github.com/skydoves/landscapist/pull/197
    • Added requestSize property to the ImageOptions and change image modifier by @skydoves in https://github.com/skydoves/landscapist/pull/198
    • Remove unused cpp classes by @skydoves in https://github.com/skydoves/landscapist/pull/199
    • Update Baseline Profiles by @skydoves in https://github.com/skydoves/landscapist/pull/200
    • Remove deprecated GlideImage and CoilImage Composables by @skydoves in https://github.com/skydoves/landscapist/pull/201
    • Fresco: honor CloseableReference and properly close it by @tkrullmann in https://github.com/skydoves/landscapist/pull/195

    New Contributors

    • @tkrullmann made their first contribution in https://github.com/skydoves/landscapist/pull/195

    Full Changelog: https://github.com/skydoves/landscapist/compare/2.0.3...2.1.0

    Source code(tar.gz)
    Source code(zip)
  • 2.0.3(Oct 25, 2022)

    What's Changed

    • Bump Compose to 1.3.0 by @skydoves in https://github.com/skydoves/landscapist/pull/190
    • Refactor image state remember extensions by @skydoves in https://github.com/skydoves/landscapist/pull/189

    Full Changelog: https://github.com/skydoves/landscapist/compare/2.0.2...2.0.3

    Source code(tar.gz)
    Source code(zip)
  • 2.0.2(Oct 16, 2022)

    Now the landscapist-transformation package is available!

    What's Changed

    • Introduce GlideRequestType which decides the result of image data by @skydoves in https://github.com/skydoves/landscapist/pull/186
    • Introduce landscapist-transformation package and BlurTransformationPlugin by @skydoves in https://github.com/skydoves/landscapist/pull/187

    BlurTransformationPlugin

    You can implement the blur effect with BlurTransformationPlugin as the following:

    GlideImage( // CoilImage, FrescoImage also can be used.
      imageModel = { poster.image },
      component = rememberImageComponent {
          +BlurTransformationPlugin(radius = 10)
      }
    )
    

    Full Changelog: https://github.com/skydoves/landscapist/compare/2.0.1...2.0.2

    Source code(tar.gz)
    Source code(zip)
  • 2.0.1(Oct 12, 2022)

    What's Changed

    • Improve internal performance of GlideImage and CoilImage by passing lambda image model by @skydoves in https://github.com/skydoves/landscapist/pull/171
    • Bump Compose to 1.3.0-beta03 by @skydoves in https://github.com/skydoves/landscapist/pull/175
    • Bump Glide to 4.14.1 by @skydoves in https://github.com/skydoves/landscapist/pull/176
    • Bump AGP to 7.3.0 by @skydoves in https://github.com/skydoves/landscapist/pull/177
    • Bump Coil to 2.2.1 by @skydoves in https://github.com/skydoves/landscapist/pull/178
    • Update Compose compiler to 1.3.2 and Kotlin to 1.7.20 by @skydoves in https://github.com/skydoves/landscapist/pull/179
    • Bump Compose UI to 1.3.0-rc01 by @skydoves in https://github.com/skydoves/landscapist/pull/180
    • Implement rememberPaletteState for Palette by @skydoves in https://github.com/skydoves/landscapist/pull/181
    • Make rememberImageComponent receiver to Composable function by @skydoves in https://github.com/skydoves/landscapist/pull/182
    • Implement Glide, Coil, Fresco image states remembering functions by @skydoves in https://github.com/skydoves/landscapist/pull/183

    Full Changelog: https://github.com/skydoves/landscapist/compare/2.0.0...2.0.1

    Source code(tar.gz)
    Source code(zip)
  • 2.0.0(Sep 12, 2022)

    🎉 Landscapist version 2.0.0 was released! 🎉

    • Introduced a new pluggable concept ImagePlugin and ImageComponent.
    • Introduced ImageOptions for configuring image composable.
    • Now, the CircularReveal, Shimmer, Placeholder, and BitmapPalette has been separated into independent modules and they were integrated with image plugins.
    • You can trace the origin of the image source with the DataSource parameter for the success state.
    • Introduced Crossfade animation.

    Quick Migration Overview

    GlideImage( // CoilImage, FrescoImage
        imageModel = poster.image,
        modifier = Modifier.aspectRatio(0.8f),
        imageOptions = ImageOptions(contentScale = ContentScale.Crop),
        component = rememberImageComponent {
          +ShimmerPlugin(
            baseColor = background800,
            highlightColor = shimmerHighLight
          )
          +PlaceholderPlugin.Failure(failurePainter)
          +PalettePlugin { palette = it }
        },
        previewPlaceholder = R.drawable.poster
    )
    

    What's Changed

    • Bump Compose UI to 1.3.0-beta01 by @skydoves in https://github.com/skydoves/landscapist/pull/153
    • Migrate Gradle files to KTS formats by @skydoves in https://github.com/skydoves/landscapist/pull/154
    • Configure version catalogs and build-logic by @skydoves in https://github.com/skydoves/landscapist/pull/155
    • Introduce landscapist-animation module and ImagePlugins by @skydoves in https://github.com/skydoves/landscapist/pull/156
    • Introduce ImageComponent and ImagePlugin to conjunct pluggable interfaces by @skydoves in https://github.com/skydoves/landscapist/pull/157
    • Introduce landscapist-placeholder and ShimmerPlugin by @skydoves in https://github.com/skydoves/landscapist/pull/158
    • Configure auto-completion exporting rules and update gitignore by @skydoves in https://github.com/skydoves/landscapist/pull/159
    • Restrict API accessibilities by annotating with InternalLandscapistApi by @skydoves in https://github.com/skydoves/landscapist/pull/160
    • Introduce PlaceholderPlugin and ImageOptions by @skydoves in https://github.com/skydoves/landscapist/pull/161
    • Add onImageStateChanged parameter to each image composables and remov… by @skydoves in https://github.com/skydoves/landscapist/pull/162
    • Update compose compiler to 1.3.1 and compose to 1.3.0-beta02 by @skydoves in https://github.com/skydoves/landscapist/pull/163
    • Introduce CrossfadePlugin by @skydoves in https://github.com/skydoves/landscapist/pull/164
    • Separate BitmapPalette into the landscapist-palette module by @skydoves in https://github.com/skydoves/landscapist/pull/165
    • Add failure cause exception to the ImageLoadState.Failure by @skydoves in https://github.com/skydoves/landscapist/pull/166
    • Add DataSource for tracing the origin of image sources by @skydoves in https://github.com/skydoves/landscapist/pull/167
    • Refactor with internal LandscapistImage by @skydoves in https://github.com/skydoves/landscapist/pull/168
    • Update BaselineProfiles by @skydoves in https://github.com/skydoves/landscapist/pull/169
    • Update README file to update 2.0.0 by @skydoves in https://github.com/skydoves/landscapist/pull/170

    Full Changelog: https://github.com/skydoves/landscapist/compare/1.6.1...2.0.0

    Source code(tar.gz)
    Source code(zip)
  • 1.6.1(Aug 11, 2022)

    What's Changed

    • Updated Compose Compiler to 1.3.0, Compose UI to 1.2.1, and Kotlin to 1.7.10 by @skydoves in https://github.com/skydoves/landscapist/pull/151

    Full Changelog: https://github.com/skydoves/landscapist/compare/1.6.0...1.6.1

    Source code(tar.gz)
    Source code(zip)
  • 1.6.0(Jul 28, 2022)

    🎉 Landscapist 1.6.0 has been released! 🎉

    What's Changed

    • Updated Compose UI to 1.2.0 and clean up Gradle files by @skydoves in https://github.com/skydoves/landscapist/pull/150
    • Mirror: Fix reacting to intrinsic size changes by @skydoves in https://github.com/skydoves/landscapist/pull/145
    • Added code blocks by @imashnake0 in https://github.com/skydoves/landscapist/pull/144

    New Contributors

    • @imashnake0 made their first contribution in https://github.com/skydoves/landscapist/pull/144

    Full Changelog: https://github.com/skydoves/landscapist/compare/1.5.3...1.6.0

    Source code(tar.gz)
    Source code(zip)
  • 1.5.3(Jul 5, 2022)

    🎉 Landscapist 1.5.3 has been released! 🎉

    What's Changed

    • Bump AGP to 7.2.0 by @skydoves in https://github.com/skydoves/landscapist/pull/129
    • Remove unnecessary load from Glide by @tkdgusl94 in https://github.com/skydoves/landscapist/pull/130
    • Update Compose version to 1.2.0-beta03 and kotlin version to 1.6.21 by @skydoves in https://github.com/skydoves/landscapist/pull/131
    • Bump Compose to 1.2.0-rc01 by @skydoves in https://github.com/skydoves/landscapist/pull/134
    • Update Compose version to 1.2.0-rc02 by @skydoves in https://github.com/skydoves/landscapist/pull/136
    • Update Compose compiler to 1.2.0 and Kotlin to 1.7.0 by @skydoves in https://github.com/skydoves/landscapist/pull/139
    • Patch 1 by @wiryadev in https://github.com/skydoves/landscapist/pull/140
    • Improve library performance with Baseline Profiles by @skydoves in https://github.com/skydoves/landscapist/pull/141
    • Mark immutable to the ShimmerParams by @skydoves in https://github.com/skydoves/landscapist/pull/142

    New Contributors

    • @tkdgusl94 made their first contribution in https://github.com/skydoves/landscapist/pull/130
    • @wiryadev made their first contribution in https://github.com/skydoves/landscapist/pull/140

    Full Changelog: https://github.com/skydoves/landscapist/compare/1.5.2...1.5.3

    Source code(tar.gz)
    Source code(zip)
  • 1.5.2(May 13, 2022)

    🎉 Landscapist 1.5.2 has been released! 🎉

    What's Changed

    • Replace BoxWithConstraints with Box by @bentrengrove in https://github.com/skydoves/landscapist/pull/126
    • Update Coil to 2.0.0 by @skydoves in https://github.com/skydoves/landscapist/pull/127
    • Bump Glide to 4.13.2 by @skydoves in https://github.com/skydoves/landscapist/pull/125
    • Configure Gradle properties by @skydoves in https://github.com/skydoves/landscapist/pull/123

    New Contributors

    • @bentrengrove made their first contribution in https://github.com/skydoves/landscapist/pull/126

    Full Changelog: https://github.com/skydoves/landscapist/compare/1.5.1...1.5.2

    Source code(tar.gz)
    Source code(zip)
  • 1.5.1(Apr 5, 2022)

    🎉 Landscapist 1.5.1 has been released! 🎉

    What's Changed

    • Update: Gradle version to 7.4.2 by @skydoves
    • Fix: Bad maven deployment after updating publish-plugin #118.
    • Migrate: the Maven publishing process and GitHub Actions by @skydoves in https://github.com/skydoves/landscapist/pull/119

    Full Changelog: https://github.com/skydoves/landscapist/compare/1.5.0...1.5.1

    Source code(tar.gz)
    Source code(zip)
  • 1.5.0(Mar 12, 2022)

    What's Changed

    • Added: RequestListener parameter for CoilImage by @skydoves in https://github.com/skydoves/landscapist/pull/115

    Full Changelog: https://github.com/skydoves/landscapist/compare/1.4.9...1.5.0

    Source code(tar.gz)
    Source code(zip)
  • 1.4.9(Mar 4, 2022)

    What's Changed

    • Updated Compose version to 1.1.1 by @skydoves in https://github.com/skydoves/landscapist/pull/113
    • Added requestListener parameter for GlideImage by @skydoves in https://github.com/skydoves/landscapist/pull/114
    • Updated Coroutines version 1.6.0 by @skydoves in https://github.com/skydoves/landscapist/pull/112

    Full Changelog: https://github.com/skydoves/landscapist/compare/1.4.8...1.4.9

    Source code(tar.gz)
    Source code(zip)
  • 1.4.8(Feb 10, 2022)

    What's Changed

    • Bump Jetpack Compose to 1.1.0 stable by @skydoves in https://github.com/skydoves/landscapist/pull/107

    Full Changelog: https://github.com/skydoves/landscapist/compare/1.4.7...1.4.8

    Source code(tar.gz)
    Source code(zip)
  • 1.4.7(Feb 8, 2022)

    What's Changed

    • Bump Glide to 4.13.0 and AGP to 7.1.0 by @skydoves in https://github.com/skydoves/landscapist/pull/106
    • Fixed placeholders to match parent size instead of using the parent Modifier by @skydoves in https://github.com/skydoves/landscapist/pull/105

    Full Changelog: https://github.com/skydoves/landscapist/compare/1.4.6...1.4.7

    Source code(tar.gz)
    Source code(zip)
  • 1.4.6(Feb 6, 2022)

    🎉 Released a new version 1.4.6! 🎉

    What's Changed

    • Bump Compose to 1.1.0-rc03 and Kotlin to 1.6.10 by @skydoves in https://github.com/skydoves/landscapist/pull/99
    • Update JVM target to 1.8 by @skydoves in https://github.com/skydoves/landscapist/pull/102
    • Change the naming convention about CircularRevelaed to CircularReveal by @skydoves in https://github.com/skydoves/landscapist/pull/103
    • Setup Dokka multi-module tasks by @skydoves in https://github.com/skydoves/landscapist/pull/96
    • Cleanup Gradle files and update spotless version by @skydoves in https://github.com/skydoves/landscapist/pull/100
    • Update Android unit test runners for Glide, Fresco, and Coil by @skydoves in https://github.com/skydoves/landscapist/pull/101

    Full Changelog: https://github.com/skydoves/landscapist/compare/1.4.5...1.4.6

    Source code(tar.gz)
    Source code(zip)
  • 1.4.5(Jan 3, 2022)

    What's Changed

    • Updated Jetpack Compose to 1.1.0-rc01 by @skydoves in https://github.com/skydoves/Landscapist/pull/94
    • Improved README and overall documentation by @skydoves
    • Updated internal Gradle plugins and dependencies by @skydoves in https://github.com/skydoves/Landscapist/pull/95

    Full Changelog: https://github.com/skydoves/Landscapist/compare/1.4.4...1.4.5

    Source code(tar.gz)
    Source code(zip)
  • 1.4.4(Dec 4, 2021)

    What's Changed

    • Bump Jetpack Compose to 1.1.0-beta04 and Koltin to 1.6.0 by @skydoves in https://github.com/skydoves/Landscapist/pull/93
    • Add BoxScope to state composables to be able to use BoxScope modifiers by @necatisozer in https://github.com/skydoves/Landscapist/pull/87
    • Change the root folder name to kotlin by @skydoves in https://github.com/skydoves/Landscapist/pull/91

    New Contributors

    • @necatisozer made their first contribution in https://github.com/skydoves/Landscapist/pull/87

    Full Changelog: https://github.com/skydoves/Landscapist/compare/1.4.3...1.4.4

    Source code(tar.gz)
    Source code(zip)
  • 1.4.3(Nov 18, 2021)

    🎉 Released a new version 1.4.3! 🎉

    What's Changed

    • Bump compose to 1.1.0-beta03 by @skydoves in https://github.com/skydoves/Landscapist/pull/86
    • Remove fillMaxSize & fillMaxWidth and use matchParentSize on BoxScope by @skydoves in https://github.com/skydoves/Landscapist/pull/85

    Full Changelog: https://github.com/skydoves/Landscapist/compare/1.4.2...1.4.3

    Source code(tar.gz)
    Source code(zip)
  • 1.4.2(Nov 10, 2021)

  • 1.4.1(Oct 31, 2021)

  • 1.4.0(Oct 27, 2021)

    🍂 A new stable 1.4.0 has been released. 🍂

    What's New?

    • Feature: A new parameter previewPlaceholder has been added for GlideImage, CoilImage, FrescoImage, and FrescoWebImage for displaying preview when this function is running on preview mode.
    Source code(tar.gz)
    Source code(zip)
  • 1.3.9(Oct 16, 2021)

  • 1.3.8(Oct 10, 2021)

    🍂 Released a new version 1.3.8! 🍂

    What's New?

    • Now CoilImage and GlideImage can receive a nullable image model.
    • Mirror: [Drawable Painter] Handle drawables with no intrinsic size (#68)
    • Updated internal JVM target to 11.
    Source code(tar.gz)
    Source code(zip)
  • 1.3.7(Oct 1, 2021)

    🍂 Released a new version 1.3.7! 🍂

    What's New?

    • Updated Jetpack Compose to 1.0.3.
    • Updated Kotlin to 1.5.30 internally.
    • Allow imageUrl to nullable parameter for FrescoImage. (#62)
    Source code(tar.gz)
    Source code(zip)
  • 1.3.6(Sep 10, 2021)

  • 1.3.5(Sep 4, 2021)

    🎉 Released a new version 1.3.5! 🎉

    What's New?

    • Now supports animated GIF and WebP images for Coil and Glide.

    Landscapist-coil supports animated GIF and WebP Images using ImageLoader.

    val context = LocalContext.current
    val imageLoader = ImageLoader.Builder(context)
      .componentRegistry {
        if (SDK_INT >= 28) {
          add(ImageDecoderDecoder(context))
        } else {
          add(GifDecoder())
        }
      }
      .build()
    
    CoilImage(
        imageModel = poster.gif, // URL of the animated images.
        imageLoader = imageLoader,
        shimmerParams = ShimmerParams(
          baseColor = background800,
          highlightColor = shimmerHighLight
        ),
        modifier = Modifier
          .fillMaxWidth()
          .padding(8.dp)
          .height(500.dp)
          .clip(RoundedCornerShape(8.dp))
      )
    
    Source code(tar.gz)
    Source code(zip)
  • 1.3.4(Aug 29, 2021)

    🎉 Released a new version 1.3.4! 🎉

    What's New?

    • Now Fresco supports animated GIF and Webp images.
    dependencies {
      implementation "com.github.skydoves:landscapist-fresco-websupport:1.3.4"
    }
    

    Fresco supports animated GIF and WebP Images using FrescoWebImage composable function. We should pass the AbstractDraweeController that can be created like the below. You can reference how to build the DraweeController, and Supported URIs for setting URI addresses. Also, we can load a normal image (jpeg, png, etc) using the custom controller.

    FrescoWebImage(
      controllerBuilder = Fresco.newDraweeControllerBuilder()
        .setUri(poster.gif) // GIF or Webp image url.
        .setAutoPlayAnimations(true),
      modifier = Modifier
        .fillMaxWidth()
        .height(300.dp)
    )
    
    Source code(tar.gz)
    Source code(zip)
  • 1.3.3(Aug 21, 2021)

    🎉 Released new version 1.3.3! 🎉

    What's New?

    • circularRevealedEnabled and circularRevealedDuration attribute has been removed. Instead, we can use CircularReveal for implementing circular reveal animation. (#41)
    GlideImage(
      imageModel = imageUrl,
      circularReveal = CircularReveal(duration = 250, onFinishListener = {  //..// } ),
    
    • Added CircularRevealFinishListener in CircularReveal. We can listen when the animation is finished.
    Source code(tar.gz)
    Source code(zip)
  • 1.3.2(Aug 12, 2021)

    🎉 Released a new version 1.3.2! 🎉

    What's New?

    • New feature: Palette (#40) @skydoves

    Palette

    We can extract major (theme) color profiles using BitmapPalette. Basically, we should use BitmapPalette for extracting the major colors from images. You can reference which kinds of colors can be extracted here.

    var palette by remember { mutableStateOf<Palette?>(null) }
    
    GlideImage( // CoilImage, FrescoImage also can be used.
      imageModel = poster?.poster!!,
      bitmapPalette = BitmapPalette {
        palette = it
      }
    )
    
    Crossfade(
      targetState = palette,
      modifier = Modifier
        .padding(horizontal = 8.dp)
        .size(45.dp)
    ) {
      Box(
        modifier = Modifier
          .background(color = Color(it?.lightVibrantSwatch?.rgb ?: 0))
          .fillMaxSize()
      )
    }
    
    Source code(tar.gz)
    Source code(zip)
  • 1.3.1(Aug 4, 2021)

Owner
Jaewoong Eum
Android and open source software engineer.❤️ Digital Nomad. Love coffee, music, magic tricks, and writing poems. Coffee Driven Development
Jaewoong Eum
An Android transformation library providing a variety of image transformations for Glide.

Glide Transformations An Android transformation library providing a variety of image transformations for Glide. Please feel free to use this. Are you

Daichi Furiya 9.7k Dec 30, 2022
load-the-image Apply to compose-jb(desktop), Used to load network and local pictures.

load-the-image load-the-image Apply to compose-jb(desktop), Used to load network and local pictures. ?? Under construction It may change incompatibly

lt_taozi 13 Dec 29, 2022
Powerful and flexible library for loading, caching and displaying images on Android.

Universal Image Loader The great ancestor of modern image-loading libraries :) UIL aims to provide a powerful, flexible and highly customizable instru

Sergey Tarasevich 16.8k Jan 8, 2023
ComposeImageBlurhash is a Jetpack Compose component with the necessary implementation to display a blurred image

compose-image-blurhash ComposeImageBlurhash is a Jetpack Compose component with the necessary implementation to display a blurred image while the real

Orlando Novas Rodriguez 24 Nov 18, 2022
An image loading and caching library for Android focused on smooth scrolling

Glide | View Glide's documentation | 简体中文文档 | Report an issue with Glide Glide is a fast and efficient open source media management and image loading

Bump Technologies 33.2k Jan 7, 2023
Library to handle asynchronous image loading on Android.

WebImageLoader WebImageLoader is a library designed to take to hassle out of handling images on the web. It has the following features: Images are dow

Alexander Blom 102 Dec 22, 2022
Glide Bitmap Pool is a memory management library for reusing the bitmap memory

Glide Bitmap Pool About Glide Bitmap Pool Glide Bitmap Pool is a memory management library for reusing the bitmap memory. As it reuses bitmap memory ,

AMIT SHEKHAR 573 Dec 31, 2022
Android Asynchronous Networking and Image Loading

Android Asynchronous Networking and Image Loading Download Maven Git Features Kotlin coroutine/suspend support Asynchronously download: Images into Im

Koushik Dutta 6.3k Dec 27, 2022
Image loading for Android backed by Kotlin Coroutines.

An image loading library for Android backed by Kotlin Coroutines. Coil is: Fast: Coil performs a number of optimizations including memory and disk cac

Coil 8.8k Jan 8, 2023
An Android view for displaying repeated continuous side scrolling images. This can be used to create a parallax animation effect.

Scrolling Image View An Android view for displaying repeated continuous side scrolling images. This can be used to create a parallax animation effect.

Q42 1.8k Dec 27, 2022
a solution that can help developers display pictures in any shape.

android-anyshape With the solution, pictures can be displayed in any shape on Android platform. Effect The left is the UI using normal ImageViews, and

Lankton 190 Dec 22, 2022
Andorid library that loads images asynchronously into cache using a thread pool

AndroidImageLoader AndroidImageLoader is a fork of the Image Loader component in libs-for-android. The AndroidImageLoader is an Android library that h

David Wu 63 Feb 19, 2019
ZoomableComposeImage - A zoomable image for jetpack compose

ZoomableComposeImage - A zoomable image for jetpack compose

RERERE 10 Dec 11, 2022
An Android library for managing images and the memory they use.

Fresco Fresco is a powerful system for displaying images in Android applications. Fresco takes care of image loading and display, so you don't have to

Facebook 16.9k Jan 8, 2023
Compose Image library for Kotlin Multiplatform.

Compose ImageLoader Compose Image library for Kotlin Multiplatform. Setup Add the dependency in your common module's commonMain sourceSet kotlin {

Seiko 45 Dec 29, 2022
Android ImageView that handles animated GIF images

GifImageView Android ImageView that handles Animated GIF images Usage In your build.gradle file: dependencies { compile 'com.felipecsl:gifimageview:

Felipe Lima 1.1k Dec 27, 2022
Media Picker is an Android Libary that lets you to select multiple images or video

Media Picker Please let me know if your application go to production via this link Media Picker is an Android Libary that lets you to select multiple

Abdullah Alhazmy 264 Nov 10, 2022
Splash - Wanted an app that displays images from Unsplash, well here it is

Splash - Wanted an app that displays images from Unsplash, well here it is

Bamidele Ajewole 2 Apr 26, 2022
A powerful image downloading and caching library for Android

Picasso A powerful image downloading and caching library for Android For more information please see the website Download Download the latest AAR from

Square 18.4k Jan 6, 2023