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

Overview

Landscapist


License API Build Status Android Weekly Profile

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

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.

Glide

Glide

Maven Central

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

allprojects {
    repositories {
        mavenCentral()
    }
}

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

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

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.
  circularRevealedEnabled = true,
  // 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(),
  transitionOptions = BitmapTransitionOptions.withCrossFade(), 
  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(LocalView.current)
    .asBitmap()
    .apply(RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL))
    .thumbnail(0.1f)
    .transition(withCrossFade()),
  modifier = Modifier.constrainAs(image) {
    centerHorizontallyTo(parent)
    top.linkTo(parent.top)
  }.aspectRatio(0.8f)
)

LocalGlideRequestBuilder

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

// customize the RequestBuilder as needed
val requestBuilder = Glide.with(LocalView.current)
  .asBitmap()
  .thumbnail(0.1f)
  .transition(BitmapTransitionOptions.withCrossFade())

CompositionLocalProvider(LocalGlideRequestBuilder provides requestBuilder) {
  // This will automatically use the value of current RequestBuilder 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.
And 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
And add a dependency code to your module's build.gradle file.

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

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.
  circularRevealedEnabled = true,
  // 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. And 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 = ...
  )
}
Fresco

Fresco

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

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

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.
  circularRevealedEnabled = true,
  // 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.
And 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(
          asset = 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 = ...
  )
}

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.
And 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 software engineer. Digital Nomad. Open Source Contributor. ❤️ Love coffee, music, magic tricks and writing poems. Coffee Driven Development.
Jaewoong Eum
Danilo Lemes 5 Jul 31, 2022
Luis David Orellana 3 Jun 20, 2022
Compose-buttons - A set of Loading animations used in Buttons to convey a "loading" state after the button is clicked.

Loading Buttons A set of Loading animations used in Buttons to convey a "loading" state after the button is clicked. A simple demo application that sh

Brad Ball 16 Jul 5, 2022
A sample project in Kotlin to demonstrate Jetpack Compose, MVVM, Coroutines, Hilt, Room, Coil, Retrofit, Moshi, Leak Canary and Repository pattern

Jetpack-Compose-Boilerplate This repository contains a sample project in Kotlin to demonstrate Jetpack Compose, MVVM, Coroutines, Hilt, Room, Coil, Re

Areg Petrosyan 14 Dec 12, 2022
Android -MVVM-Jetpack Compose-Kotlin Flows-Dagger Hilt-Retrofilt2-Coil

android-mvvm-jetpack-compose-kotlin-flows Android -MVVM-Jetpack Compose-Kotlin Flows-Dagger Hilt-Retrofilt2-Coil A sample project that presents a mode

Emad Seliem 8 Jul 27, 2022
android project themplate including network(retrofit), utils(image, permission, etc), etc

Template-Android When starting a new Android project, it is boring to write some codes such as permission verification, network interface creation, wh

null 2 Oct 29, 2022
🚀🌆🏙 Display differences or animate progress between 2 images or Composables with overlay and customization options, zoom, pan gestures, and progress to observe properties for animating before-after progress

Compose Before-After Composables to display Images, or Composables as before and after composables to display differences or animate progress between

Smart Tool Factory 56 Dec 22, 2022
A collection of animations, compositions, UIs using Jetpack Compose. You can say Jetpack Compose cookbook or play-ground if you want!

Why Not Compose! A collection of animations, compositions, UIs using Jetpack Compose. You can say Jetpack Compose cookbook or play-ground if you want!

Md. Mahmudul Hasan Shohag 186 Jan 1, 2023
Demo project for a bug in coil:2.0.0-alpha06

Demo Project for Coil alpha06 issue This is a demo project for an issue in coil:

Tobias Herrmann 0 Jan 12, 2022
🎨 Jetpack Compose canvas library that helps you draw paths, images on canvas with color pickers and palettes

?? Jetpack Compose canvas library that helps you draw paths and images on canvas with color pickers and palettes. Sketchbook also provides useful components and functions that can easily interact with canvas.

Stream 342 Dec 30, 2022
Jetpack Compose animations including Loading/progress, Looping, On-off, Enter, Exit, Fade, Spin and Background animation

Compose Animation Examples. Useful Jetpack Compose animations including Loading/progress, Looping, On-off, Enter, Exit, Fade, Spin and Background animations that you can take inspiration from.

Mutual Mobile 149 Dec 22, 2022
A simple authentication application using Jetpack compose to illustrate signin and sign up using Mvvm, Kotlin and jetpack compose

Authentication A simple authentication application using Jetpack compose to illustrate signin and sign up using Mvvm, Kotlin and jetpack compose Scree

Felix Kariuki 5 Dec 29, 2022
Jetpack Compose Boids | Flocking Insect 🐜. bird or Fish simulation using Jetpack Compose Desktop 🚀, using Canvas API 🎨

?? ?? ?? Compose flocking Ants(boids) ?? ?? ?? Jetpack compose Boids | Flocking Insect. bird or Fish simulation using Jetpack Compose Desktop ?? , usi

Chetan Gupta 38 Sep 25, 2022
Jetpack-compose-uis - A collection of some UIs using Jetpack Compose. built using Katalog

Jetpack Compose UIs This is a collection of some UIs using Jetpack Compose. It i

Mori Atsushi 3 Dec 15, 2022
It's a simple app written in Kotlin that shows a simple solution for how to save an image into Firebase Storage, save the URL in Firestore, and read it back using Jetpack Compose.

It's a simple app written in Kotlin that shows a simple solution for how to save an image into Firebase Storage, save the URL in Firestore, and read it back using Jetpack Compose.

Alex 10 Dec 29, 2022
🚀🏞💪 Collection of Images, Modifiers, utility functions for Jetpack Compose to expand and enrich displaying, manipulating, scaling, resizing, zooming, and getting cropped ImageBitmap based on selection area

Collection of Images, Modifiers, utility functions for Jetpack Compose to expand and enrich displaying, manipulating, scaling, resizing, zooming, and getting cropped ImageBitmap based on selection area, before/after image to with handle to show partial of both images and more is cooking up

Smart Tool Factory 207 Dec 26, 2022
Zoom Modifiers, zoomable image and layouts with limit pan bounds, fling and moving back to valid bounds and callbacks that return current transformation or visible image section

Zoom Modifiers, zoomable image and layouts with limit pan bounds, fling and moving back to valid bounds and callbacks that return current transformation or visible image section

Smart Tool Factory 20 Dec 13, 2022
Burak Akgün 84 Oct 30, 2022
A 7 and 14 segment display for Android built with Jetpack Compose

SegmentedDisplay A 7-segment and 14-segment display for Android build with Jetpack Compose Customizable Highly customisable. Hook up to a data stream

Rab Ross 5 May 23, 2022