saket / telephoto

Building blocks for designing media experiences in Compose UI
https://saket.github.io/telephoto/
Apache License 2.0
996 stars 32 forks source link

Crash when using custom Uris #51

Closed janbina closed 4 months ago

janbina commented 1 year ago

In our app, we are using uris with custom scheme to fetch a specific type of images. They are of this form:

localdb://poiimageprovider/image-data?requestid=...

We then have a Fetcher for coil that loads the image data from database, something like

class DbUriFetcherFactory : Fetcher.Factory<Uri> {
  override fun create(data: Uri, options: Options, imageLoader: ImageLoader): Fetcher {
    return Fetcher {
      if (data.scheme == "localdb") {
        // load data and return `SourceResult`
      } else null
    }
  }
}

This works fine with coil, but telephoto tries to access the uri using ContentResolver and crashes:

java.io.FileNotFoundException: No content provider: localdb://poiimageprovider/image-data?requestid=...
at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:2029)
at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1858)
at android.content.ContentResolver.openInputStream(ContentResolver.java:1528)
at me.saket.telephoto.subsamplingimage.UriImageSource.peek(SubSamplingImageSource.kt:187)
at me.saket.telephoto.zoomable.coil.SubSamplingEligibilityKt.isSvg(subSamplingEligibility.kt:56)
at me.saket.telephoto.zoomable.coil.SubSamplingEligibilityKt.canBeSubSampled(subSamplingEligibility.kt:26)
at me.saket.telephoto.zoomable.coil.Resolver.toSubSamplingImageSource(CoilImageSource.kt:153)
at me.saket.telephoto.zoomable.coil.Resolver.work(CoilImageSource.kt:109)

I'm not quite sure whether this should work or not, our solution is probably not great and maybe we should actually use ContentProvider for our uris instead of Fetcher, but it worked so far 😀 For now we fixed that by using model class instead of plain Uri.

saket commented 1 year ago

Yea telephoto is currently unaware of custom Coil fetchers for loading images. If it sees an Uri, it expects the app to provide a content provider for reading its content.

I could potentially check for Uris that use schemes unsupported by ContentResolver and read them using coil's fetchers instead. Wanna help me out? I'd start here:

https://github.com/saket/telephoto/blob/25b42e44239a529efcfb4d2d87b97f2646050446/zoomable-image/coil/src/main/kotlin/me/saket/telephoto/zoomable/coil/CoilImageSource.kt#L199

Alternatively, can your custom fetcher return a diskCacheKey? Reading images from the disk is significantly faster than reading them through input streams.

https://github.com/saket/telephoto/blob/25b42e44239a529efcfb4d2d87b97f2646050446/zoomable-image/coil/src/main/kotlin/me/saket/telephoto/zoomable/coil/CoilImageSource.kt#L132

saket commented 4 months ago

Closing due to inactivity, but feel free to reopen?