Git Product home page Git Product logo

zoomable's Issues

How to zoom at the center of the image programmatically

I've take a look at this PR. According to this I can use

zoomState.changeScale(
     zoomstate.scale * 2,
     Offset(X,Y),
)

Where X and Y would be if I understood it correctly. @usuiat Is the formula looks correct to you?

X = (w∗scale−w)/2
Y = (h∗scale−h)/2

Currently cant access the layout size from the zoomState. How can I achieve this?

[Feature Request] Add single tap support

There's some cases like the Gallery use case where the user can toggle systemui on single tap

I've tried adding the onSingleTap unit in the library but there's a small bug where if the zoom is quite high (> 5f), and a single tap is registered, there's a slight movement in the offset on every tap

Example code:

private suspend fun PointerInputScope.detectTransformGestures(
    ..
    onSingleTap: () -> Unit = {},
    enableOneFingerZoom: Boolean = true,
) = awaitEachGesture {
     ..
     if (isTap) {
     // Vertical scrolling following a double tap is treated as a zoom gesture.
        if (enableOneFingerZoom) {
        val secondDown = awaitSecondDown(firstUp)
            if (secondDown != null) {
                ..
            } else onSingleTap()
        ..
        } else onSingleTap()
     }
     
     onGestureEnd()
}

Single Tap isn't strict

Preconditions:

  • I was trying to implement similar behavior as described in #65 issue.
  • I have HorizontalPager with pictures and I want to toggle UI on tap.
  • Version of Zoomable: 1.6.0
  • Version of Compose Foundation (contains Pager): 1.6.2
  • Device: Pixel 8, Android 14

Problem:
I faced the issue when onTap callback invokes by swipe gesture, not a tap.
It reproduces when you swipe slightly so Pager even doesn't change the page.

You can see it on the video:

video_2024-03-03_14-45-21.mp4

Code:

HorizontalPager(
    state = pagerState,
    modifier = Modifier.fillMaxSize()
) { page ->
    val zoomState = rememberZoomState()
    AsyncImage(
        model = state.picturesUri[page],
        contentDescription = null,
        onSuccess = { pictureState -> zoomState.setContentSize(pictureState.painter.intrinsicSize) },
        contentScale = ContentScale.Fit,
        modifier = Modifier
            .fillMaxSize()
            .zoomable(
                zoomState = zoomState,
                enableOneFingerZoom = false,
                onTap = {
                    Log.d("MyTag", "onTap() triggered")
                    onPagerClick() // <<< Hide UI in onPagerClick()
                },
            )
        )
}

Ask:
Could you please make the onTap callback more strict, so it doesn't trigger with slight swipes?

Individual Zoom for Canvas Rectangles using rememberZoomState.

Hi!

I'm trying to add zoom to the rectangles I drew with canvas, using rememberZoomState. However, when I zoom in one, it zooms in all of them, and the idea is to zoom them individually.

I know I could do something similar using pointerInput, but the idea is to use the library.

Could you tell me if this would be possible?

My Code:

@Composable
internal fun ScreenShotDrawSpeech(
    bubbleDomain: BubbleDomain,
    modifier: Modifier = Modifier,
) {
    val textMeasurer = rememberTextMeasurer()
    val zoom = rememberZoomableState()

    Canvas(
        modifier = modifier
            .fillMaxSize()
            .background(background_overlay)
            .zoomable(zoom),
        onDraw = {
            bubbleDomain.predictions.forEach { prediction ->
                val left = prediction.x - prediction.width / 2
                val top = prediction.y - prediction.height / 2
                val right = left + prediction.width
                val bottom = top + prediction.height

                val rect = Rect(left.toInt(), top.toInt(), right.toInt(), bottom.toInt())

                drawSpeechBoundingBox(text = prediction.confidence.toString(), boundingBox = rect, textMeasurer = textMeasurer)
            }
        },
    )
}

Gestures stops working in HorizontalPager with Compose 1.5.0

Modifier.zoomable stops working after swipeing the page of HorizontalPager.

With compose 1.5.0, this issue occurs. (I confirmed with 1.5.0-beta02)
With compose 1.4.3, it does not occur.

This may be a problem on the compose library side, but I will also investigate if it is possible to work around it on the Zoomable side.
If you know more information please let me know.

Related issues

Support Swipe-to-Dismiss behavior

Feature request:
I would like to ask it is possible to support Swipe-to-Dismiss behavior in Zoomable library?

I see the API like this:

val zoomState = rememberZoomState()

Modifier.zoomable(
    zoomState = zoomState,
    // enables behavior
    enableDismissGesture = true,
    // callback for progress listening, may be needed for changing background alpha
    // provides value between 0F and 1F
    onDismissProgressChange = { progress: Float -> Log.d("MyTag", "Dismiss progress $progress") },
    // triggers when progress reaches 1F
    onDismiss = { Log.d("MyTag, "Dismissed" },
),

Similar behavior you can see in Telegram or at the video:

video_2024-03-08_15-44-26.mp4

Support for boundary clip

We can now use

Modifier
   .clipToBounds()
   .zoomable(zoomState = zoomState)

but it will be good if we can use it like that

Modifier
   .zoomable(
        zoomState = zoomState, 
        clip = true
   )

Key param

It would be really helpful to have key parameter which by it's changing resets zoom state to initial position

Min/Max scale

is it possible to Expose maxScale property and also add minScale?

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.github/workflows/publish-docs.yml
  • actions/checkout v4
  • actions/setup-java v4
  • peaceiris/actions-gh-pages v3
.github/workflows/test.yml
  • actions/checkout v4
  • actions/setup-java v4
gradle
gradle.properties
settings.gradle
build.gradle
app/build.gradle
gradle/libs.versions.toml
  • androidx.compose.animation:animation-core 1.7.0-alpha06
  • androidx.compose.foundation:foundation 1.7.0-alpha06
  • androidx.compose.runtime:runtime 1.7.0-alpha06
  • androidx.compose.ui:ui 1.7.0-alpha06
  • androidx.compose.ui:ui-test-junit4 1.7.0-alpha06
  • androidx.compose.ui:ui-test-manifest 1.7.0-alpha06
  • androidx.compose.ui:ui-tooling 1.7.0-alpha06
  • androidx.compose.ui:ui-tooling-preview 1.7.0-alpha06
  • androidx.compose.ui:ui-util 1.7.0-alpha06
  • androidx.compose.material3:material3 1.2.1
  • androidx.activity:activity-compose 1.8.2
  • androidx.core:core-ktx 1.12.0
  • androidx.lifecycle:lifecycle-runtime-ktx 2.7.0
  • androidx.test.ext:junit 1.1.5
  • androidx.test.espresso:espresso-core 3.5.1
  • com.google.accompanist:accompanist-pager 0.34.0
  • com.google.accompanist:accompanist-pager-indicators 0.34.0
  • io.coil-kt:coil-compose 2.6.0
  • junit:junit 4.13.2
  • org.jetbrains.kotlinx:kotlinx-coroutines-test 1.8.1
  • org.robolectric:robolectric 4.12.1
  • com.android.application 8.4.0
  • com.android.library 8.4.0
  • org.jetbrains.kotlin.android 1.9.23
  • com.vanniktech.maven.publish 0.28.0
  • org.jetbrains.dokka 1.9.20
zoomable/build.gradle
gradle-wrapper
gradle/wrapper/gradle-wrapper.properties
  • gradle 8.7

  • Check this box to trigger a request for Renovate to run again on this repository

Support for KMP

Java/Android compose ui tooling library references are preventing the library from being a pure kotlin multiplatform library

Gestures stops working in HorizontalPager

androidx foundation version : 1.5.0-beta01 (there's some api changes regarding the pager)
androidx material3 version : 1.1.0-alpha01

Zoomable modifier and gestures works just fine with scrolling for the first 2 pages on latest HorizontalPager, then it stops registering the gesture (clicks still works). In order to restore the functionality a configuration changes is required (rotate screen for ex).

I suspect the 1.5.0-beta01 is the culprit, but I would like your opinion regarding a possible fix regarding this sudden lack of registration.

After some debugging found out that the gesture is happening, but it cancels/stops just before zoomState.applyGesture in Zoomable.kt

Loading high resolutions images leads to crash

Loading high resolution images (e.g. panoramas) to Image or AsyncImage composable with zoomable modifier leads to crash. Removing zoomable modifier fixes the crash. It seems, that "maximum supported resolution" depends on device.

FATAL EXCEPTION: main
Process: menion.android.locus.test, PID: 19507
java.lang.RuntimeException: Canvas: trying to draw too large(124467200bytes) bitmap.
	at android.graphics.RecordingCanvas.throwIfCannotDraw(RecordingCanvas.java:280)
	at android.graphics.BaseRecordingCanvas.drawBitmap(BaseRecordingCanvas.java:88)
	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:40)
	at androidx.compose.ui.graphics.drawscope.DrawScope.drawImage-AZ2fEMs$default(DrawScope.kt:510)
	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 coil.compose.AsyncImagePainter.onDraw(AsyncImagePainter.kt:207)
	at androidx.compose.ui.graphics.painter.Painter.draw-x_KDEd0(Painter.kt:212)
	at androidx.compose.ui.draw.PainterNode.draw(PainterModifier.kt:342)
	at androidx.compose.ui.node.LayoutNodeDrawScope.drawDirect-x_KDEd0$ui_release(LayoutNodeDrawScope.kt:105)
	at androidx.compose.ui.node.LayoutNodeDrawScope.draw-x_KDEd0$ui_release(LayoutNodeDrawScope.kt:86)
	at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:365)
	at androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:354)
	at androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:182)
	at androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:362)
	at androidx.compose.ui.node.NodeCoordinator.access$drawContainedDrawModifiers(NodeCoordinator.kt:54)
	at androidx.compose.ui.node.NodeCoordinator$invoke$1.invoke(NodeCoordinator.kt:384)
	at androidx.compose.ui.node.NodeCoordinator$invoke$1.invoke(NodeCoordinator.kt:383)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2299)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:467)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:230)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.NodeCoordinator.invoke(NodeCoordinator.kt:383)
	at androidx.compose.ui.node.NodeCoordinator.invoke(NodeCoordinator.kt:54)
	at androidx.compose.ui.platform.RenderNodeApi29.record(RenderNodeApi29.android.kt:209)
	at androidx.compose.ui.platform.RenderNodeLayer.updateDisplayList(RenderNodeLayer.android.kt:305)
	at androidx.compose.ui.platform.AndroidComposeView.dispatchDraw(AndroidComposeView.android.kt:1138)
	at android.view.View.draw(View.java:21428)
	at android.view.View.updateDisplayListIfDirty(View.java:20302)
	at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4372)
	at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4345)
	at android.view.View.updateDisplayListIfDirty(View.java:20262)
	at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4372)
	at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4345)
	at android.view.View.updateDisplayListIfDirty(View.java:20262)
	at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4372)
	at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4345)
	at android.view.View.updateDisplayListIfDirty(View.java:20262)
	at android.view.View.draw(View.java:21157)
	at android.view.ViewGroup.drawChild(ViewGroup.java:4388)
	at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4149)
	at android.view.View.draw(View.java:21428)
	at com.android.internal.policy.DecorView.draw(DecorView.java:806)
	at android.view.View.updateDisplayListIfDirty(View.java:20302)
	at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:575)
	at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:581)
	at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:654)
	at android.view.ViewRootImpl.draw(ViewRootImpl.java:3608)
	at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:3416)
	at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2753)
	at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1719)
	at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7602)
	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1041)
	at android.view.Choreographer.doCallbacks(Choreographer.java:864)
	at android.view.Choreographer.doFrame(Choreographer.java:799)
	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1026)
	at android.os.Handler.handleCallback(Handler.java:883)
	at android.os.Handler.dispatchMessage(Handler.java:100)
	at android.os.Looper.loop(Looper.java:214)
	at android.app.ActivityThread.main(ActivityThread.java:7397)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)

Zoom is spreading over other composables

Applying the zoom modifier to an image in the sample app also affects other composables. For instance, when I added a column below the AsyncImage, the image overlapped over the other composable on zooming. I don't know if this is a bug or intended behavior.

How do you keep the zoom in the image bound itself?

Sample Code App with the Text in Column

/**
 * Sample that shows a zoomable image asynchronously.
 *
 * [Modifier.zoomable] modifies Coil library's [AsyncImage] composable.
 * setContentSize() will be called when the image data is loaded.
 */
@Composable
fun AsyncImageSample(onTap: (Offset) -> Unit) {
    val zoomState = rememberZoomState()
    Column {
        AsyncImage(
            model = "https://github.com/usuiat.png",
            contentDescription = "GitHub icon",
            contentScale = ContentScale.Fit,
            onSuccess = { state ->
                zoomState.setContentSize(state.painter.intrinsicSize)
            },
            modifier = Modifier
                .size(400.dp)
                .zoomable(
                    zoomState = zoomState,
                    onTap = onTap
                ),
        )
        Column(
            modifier = Modifier
                .height(200.dp)
                .fillMaxWidth()
                .background(Color.Red),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = androidx.compose.foundation.layout.Arrangement.Center

        ) {
            Text(
                text = "This is zoomable image asynchronously.",
                textAlign = TextAlign.Center,
            )

        }
    }
}

Proof:

Screen.Recording.2024-04-04.at.4.12.31.PM.mov

Rotation

Is it possible to add rotation? (i know it is :))

Delay between double tap zoom is too long

I'm using coil's AsyncImages inside an HorizontalPager but since the time between the double tap zoom is kinda long, swiping relatively fast leads to unwanted zooms.
Im pretty sure this can be fixed by making the time between the 2 taps shorter.

Example: https://gyazo.com/2bc85ed503b4d5ab4772b610accbcd0d
In this example i wasn't trying to zoom in the images, but just to swipe between them.
Could you please fix it?

Change branch operation policy

Currently the alpha version support of Compose has been included in the main branch.
This makes it difficult to add new features.
Therefore, I will change the branch operation.

  • Move the alpha version support of Compose to a dedicated branch.
  • Merge v1.4.x support of Compose to the main branch.

How to prevent over-panning?

Hello.

First and foremost, thank you for your library. It has helped me to implement a gallery viewer with zoom and pan. However, I found for my use case there is only one small issue. Whenever the image is zoomed, I have this effect:

video_1.mp4

I believe this is called over-panning, though I'm not sure. Instead, I'm trying to get something were there is this kind of edge detection:

video_2.mp4

That was achieved using the well known TouchImageView library. However, I would like to prefer a pure Jetpack Compose solution.

Thanks in advance.

Zoom on double tap

onDoubleTap = { position ->
    when (zoomState.scale) {
        in 1f..<5f -> {
            zoomState.changeScale(5f, position)
        }
        in 5f..<10f -> {
            zoomState.changeScale(10f, position)
        }
        else -> {
            zoomState.changeScale(1f, position)
        }
    }
}

if there will be parameter level, then it will be easeir to manage, like

onDoubleTap = { position, level ->
    when (level) {
        ZoomLevel.Min -> {
            zoomState.changeScale(1f, position)
        }
        ZoomLevel.Mid-> {
            zoomState.changeScale(5f, position)
        }
        ZoomLevel.Max-> {
            zoomState.changeScale(10f, position)
        }
    }
}

code fix suggestion

Hi !
I have a question.
applyGesture function in ZoomState class:

as-is

velocityTracker.addPosition(timeMillis, position)

to-be

velocityTracker.addPosition(timeMillis, newOffset)

Isn't this correct?

Fix vertical scroll getting locked in a scrollable composable

I'm attempting to use Zoomable in a LazyColumn which is itself scrollable. I wrapped the LazyColumn in a BoxWithConstraints so that I can set the contentSize of the ZoomState and it's easier to figure out the bounds of the zoomable modifier.

Something like this:

BoxWithConstraints(modifier = modifier) {
   val width = maxWidth
   val pageAspectRatio = 1f / sqrt(2f)
   val height = width / pageAspectRatio
   val zoomState = rememberZoomState(
            contentSize = Size(
                width = width.toFloat(),
                height = height.toFloat()
            )
        )
   LazyColumn(
        modifier = Modifier.zoomable(
            zoomState = zoomState,
            enableOneFingerZoom = false,
        ),
        content = {...}
    )
}

Everything seems to work well, except one thing.

After zooming in (don't zoom in too much, just a little bit), it seems that the vertical scroll of a continuous gesture is constrained. You can scroll for a little bit, but after a continuous scroll, the vertical gesture is consumed without scrolling further. It's as if zoomable will allow the scrolling only for the amount of the zoomed content size, and then will consume the rest of the scroll gesture instead of letting the LazyColumn handle it.

This behavior doesn't trigger in case of a fling gesture (I'm guessing it's because it's handled by the LazyColumn directly.

State Restoration

add rememberSaveable instead of remember and option to control it

Zooming image and swiping page occur at same time

Pinch gestures to an Image placed on a HorizontalPager may cause the image to expand and the page to swipe at the same time.
While pinch gestures are detected, swiping page should be disabled.

Attached is a video of this issue. it is slow playback.

zoom_and_swipe.mp4

Notify on scale changes

Hey,
I have an UI element over the zoomable Image, that I want to hide or show depending if the image is zoomed in or out.
I don't see a direct way to observe the scale changes at this moment. Would it be possible to f.e. add a callback for scale changes?

Paparazzi screenshot test failing

When I use zoomState.setContentSize(state.painter.intrinsicSize), the paparazzi screenshots fail and I receive an error message

Apr 08, 2024 11:23:41 AM app.cash.paparazzi.internal.PaparazziLogger logAndroidFramework
INFO: Settings [3]: Can't get key animator_duration_scale from content://settings/global
-_- scale 1.0
Apr 08, 2024 11:23:41 AM app.cash.paparazzi.internal.PaparazziLogger error
SEVERE: broken: View measure failed
java.lang.IllegalStateException: Size is unspecified
	at androidx.compose.ui.geometry.Size.getWidth-impl(Size.kt:48)
	at net.engawapg.lib.zoomable.ZoomState.updateFitContentSize(ZoomState.kt:121)
	at net.engawapg.lib.zoomable.ZoomState.setLayoutSize-uvyYCjk(ZoomState.kt:96)
	at net.engawapg.lib.zoomable.ZoomableNode.measure-3p2s80s(Zoomable.kt:443)
	at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
	at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:646)
	at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
	at androidx.compose.foundation.layout.FillNode.measure-3p2s80s(Size.kt:699)
	at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2303)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:500)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:256)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
	at androidx.compose.foundation.layout.BoxMeasurePolicy.measure-3p2s80s(Box.kt:144)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.foundation.layout.FillNode.measure-3p2s80s(Size.kt:699)
	at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2303)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:500)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:256)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
	at androidx.compose.foundation.layout.RowColumnMeasurementHelper.measureWithoutPlacing-_EkL_-Y(RowColumnMeasurementHelper.kt:172)
	at androidx.compose.foundation.layout.RowColumnMeasurePolicy.measure-3p2s80s(RowColumnImpl.kt:72)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.foundation.layout.FillNode.measure-3p2s80s(Size.kt:699)
	at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
	at androidx.compose.foundation.layout.FillNode.measure-3p2s80s(Size.kt:699)
	at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2303)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:500)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:256)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
	at androidx.compose.foundation.layout.RowColumnMeasurementHelper.measureWithoutPlacing-_EkL_-Y(RowColumnMeasurementHelper.kt:112)
	at androidx.compose.foundation.layout.RowColumnMeasurePolicy.measure-3p2s80s(RowColumnImpl.kt:72)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:646)
	at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
	at androidx.compose.foundation.layout.SizeNode.measure-3p2s80s(Size.kt:838)
	at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
	at androidx.compose.foundation.layout.SizeNode.measure-3p2s80s(Size.kt:838)
	at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2303)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:500)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:256)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
	at androidx.compose.ui.layout.RootMeasurePolicy.measure-3p2s80s(RootMeasurePolicy.kt:38)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2303)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:500)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:256)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release(LayoutNode.kt:1145)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-sdFAvZA(MeasureAndLayoutDelegate.kt:354)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureOnly(MeasureAndLayoutDelegate.kt:562)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureOnly(MeasureAndLayoutDelegate.kt:407)
	at androidx.compose.ui.platform.AndroidComposeView.onMeasure(AndroidComposeView.android.kt:1058)
	at android.view.View.measure_Original(View.java:26358)
	at android.view.View_Delegate.measure(View_Delegate.java:80)
	at android.view.View.measure(View.java:26322)
	at androidx.compose.ui.platform.AbstractComposeView.internalOnMeasure$ui_release(ComposeView.android.kt:302)
	at androidx.compose.ui.platform.AbstractComposeView.onMeasure(ComposeView.android.kt:289)
	at android.view.View.measure_Original(View.java:26358)
	at android.view.View_Delegate.measure(View_Delegate.java:80)
	at android.view.View.measure(View.java:26322)
	at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
	at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
	at android.view.View.measure_Original(View.java:26358)
	at android.view.View_Delegate.measure(View_Delegate.java:80)
	at android.view.View.measure(View.java:26322)
	at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
	at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
	at android.view.View.measure_Original(View.java:26358)
	at android.view.View_Delegate.measure(View_Delegate.java:80)
	at android.view.View.measure(View.java:26322)
	at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:735)
	at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:481)
	at android.view.View.measure_Original(View.java:26358)
	at android.view.View_Delegate.measure(View_Delegate.java:80)
	at android.view.View.measure(View.java:26322)
	at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6981)
	at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
	at android.view.View.measure_Original(View.java:26358)
	at android.view.View_Delegate.measure(View_Delegate.java:80)
	at android.view.View.measure(View.java:26322)
	at com.android.layoutlib.bridge.impl.RenderSessionImpl.measureView(RenderSessionImpl.java:678)
	at com.android.layoutlib.bridge.impl.RenderSessionImpl.measureLayout(RenderSessionImpl.java:261)
	at com.android.layoutlib.bridge.impl.RenderSessionImpl.renderAndBuildResult(RenderSessionImpl.java:518)
	at com.android.layoutlib.bridge.impl.RenderSessionImpl.render(RenderSessionImpl.java:468)
	at app.cash.paparazzi.Paparazzi$takeSnapshots$1$3.invoke(Paparazzi.kt:344)
	at app.cash.paparazzi.Paparazzi$takeSnapshots$1$3.invoke(Paparazzi.kt:343)
	at app.cash.paparazzi.Paparazzi.withTime(Paparazzi.kt:391)
	at app.cash.paparazzi.Paparazzi.takeSnapshots(Paparazzi.kt:343)
	at app.cash.paparazzi.Paparazzi.snapshot(Paparazzi.kt:226)
	at app.cash.paparazzi.Paparazzi.snapshot$default(Paparazzi.kt:225)
	at app.cash.paparazzi.Paparazzi.snapshot(Paparazzi.kt:221)
	at app.cash.paparazzi.Paparazzi.snapshot$default(Paparazzi.kt:217)
	at a.b.c.screenViewSnapshot(GYGScreenshotHelper.kt:98)
	at a.b.c.SeatMapBottomSheetScreenshot.seatMapBottomSheet(SeatMapBottomSheetScreenshot.kt:28)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at app.cash.paparazzi.Paparazzi$apply$1.evaluate(Paparazzi.kt:156)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runners.Suite.runChild(Suite.java:128)
	at org.junit.runners.Suite.runChild(Suite.java:27)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
	at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:42)
	at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:80)
	at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:72)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:119)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:94)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:89)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:62)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
	at jdk.proxy2/jdk.proxy2.$Proxy5.stop(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
	at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:113)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65)
	at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
	at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)

Apr 08, 2024 11:23:41 AM app.cash.paparazzi.internal.PaparazziLogger error
SEVERE: broken: Failed executing Choreographer#doFrame
java.lang.IllegalArgumentException: Width (1080) and height (0) cannot be <= 0
	at java.desktop/java.awt.image.DirectColorModel.createCompatibleWritableRaster(Unknown Source)
	at java.desktop/java.awt.image.BufferedImage.<init>(Unknown Source)
	at com.android.layoutlib.bridge.impl.RenderSessionImpl.renderAndBuildResult(RenderSessionImpl.java:543)
	at com.android.layoutlib.bridge.impl.RenderSessionImpl.render(RenderSessionImpl.java:468)
	at app.cash.paparazzi.Paparazzi$takeSnapshots$1$3.invoke(Paparazzi.kt:344)
	at app.cash.paparazzi.Paparazzi$takeSnapshots$1$3.invoke(Paparazzi.kt:343)
	at app.cash.paparazzi.Paparazzi.withTime(Paparazzi.kt:391)
	at app.cash.paparazzi.Paparazzi.takeSnapshots(Paparazzi.kt:343)
	at app.cash.paparazzi.Paparazzi.snapshot(Paparazzi.kt:226)
	at app.cash.paparazzi.Paparazzi.snapshot$default(Paparazzi.kt:225)
	at app.cash.paparazzi.Paparazzi.snapshot(Paparazzi.kt:221)
	at app.cash.paparazzi.Paparazzi.snapshot$default(Paparazzi.kt:217)
	at a.b.c.screenViewSnapshot(GYGScreenshotHelper.kt:98)
	at a.b.c.seatMapBottomSheet(SeatMapBottomSheetScreenshot.kt:28)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at app.cash.paparazzi.Paparazzi$apply$1.evaluate(Paparazzi.kt:156)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runners.Suite.runChild(Suite.java:128)
	at org.junit.runners.Suite.runChild(Suite.java:27)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
	at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:42)
	at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:80)
	at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:72)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:119)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:94)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:89)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:62)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
	at jdk.proxy2/jdk.proxy2.$Proxy5.stop(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
	at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:113)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65)
	at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
	at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)


java.lang.IllegalArgumentException: Width (1080) and height (0) cannot be <= 0
	at java.desktop/java.awt.image.DirectColorModel.createCompatibleWritableRaster(Unknown Source)
	at java.desktop/java.awt.image.BufferedImage.<init>(Unknown Source)
	at com.android.layoutlib.bridge.impl.RenderSessionImpl.renderAndBuildResult(RenderSessionImpl.java:543)
	at com.android.layoutlib.bridge.impl.RenderSessionImpl.render(RenderSessionImpl.java:468)
	at app.cash.paparazzi.Paparazzi$takeSnapshots$1$3.invoke(Paparazzi.kt:344)
	at app.cash.paparazzi.Paparazzi$takeSnapshots$1$3.invoke(Paparazzi.kt:343)
	at app.cash.paparazzi.Paparazzi.withTime(Paparazzi.kt:391)
	at app.cash.paparazzi.Paparazzi.takeSnapshots(Paparazzi.kt:343)
	at app.cash.paparazzi.Paparazzi.snapshot(Paparazzi.kt:226)
	at app.cash.paparazzi.Paparazzi.snapshot$default(Paparazzi.kt:225)
	at app.cash.paparazzi.Paparazzi.snapshot(Paparazzi.kt:221)
	at app.cash.paparazzi.Paparazzi.snapshot$default(Paparazzi.kt:217)
	at a.b.cGYGScreenshotHelper.screenViewSnapshot(GYGScreenshotHelper.kt:98)
	at a.b.c.seatMapBottomSheet(SeatMapBottomSheetScreenshot.kt:28)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at app.cash.paparazzi.Paparazzi$apply$1.evaluate(Paparazzi.kt:156)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runners.Suite.runChild(Suite.java:128)
	at org.junit.runners.Suite.runChild(Suite.java:27)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
	at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:42)
	at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:80)
	at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:72)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:119)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:94)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:89)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:62)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
	at jdk.proxy2/jdk.proxy2.$Proxy5.stop(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
	at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:113)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65)
	at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
	at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)


Consider supporting Compose Desktop?

I've made a copy of the 2 files in my desktop project, by removing the "fast" variants of any and forEach I got something working very quickly. Just wanted to share that quick experiment.

onTouchEvent is not broadcasted to the view when the view is zoomed

Hello,

I have integrated the library in my project and I apply it to an AndroidView :

AndroidView(
    modifier = modifier
      .zoomable(
        zoomState = zoomState,
        enableOneFingerZoom = false,
      ),
    factory = {
      MyCustomRelativeLayout(it).apply {
        layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
      }
    },
    update = {
     //...
    }
  )

The MyCustomRelativeLayout is a ViewGroup that extends RelativeLayout in which on the onTouchEvent(MotionEvent event) method is overrided.

When my custom view is not zoomed, the touch event is correctly triggered. But when the view is zoomed, the onTouchEvent of my custom view is not called anymore.

How can I update the library to trigger the onTouchEvent regardless of the view zoom level?

Thank you for your help.

Support lower compileSdk version

Hi,

I came across this library, and I'm really impressed with its design. However, I'm facing an issue with importing it into my project due to its dependency on 'androidx.emoji2:emoji2:1.4.0,' which requires an update to compile version 34. This dependency seems unrelated to the primary purpose of this library, which feels a bit unusual.

Additionally, upgrading my current project to compileSdk version 34 is quite time-consuming.

Therefore, I would like to inquire if it's possible for the library to provide documentation support for lower versions, like compileSdk version 33. I'm wondering if this request is feasible.

Thank you.

[FR]: Support double-tap zoom

Is there an existing issue for this?

  • I have searched the existing issues

Describe the problem

As of now, Zoomable supports a "double-tap + drag" zoom. Is it possible to support the arguably more usual "double-tap" zoom?
For example, it's a feature supported by PhotoView or Discord's image viewer.

Describe the solution

How it works:

Thanks.

Can't implementation Zoomble library from mavenCentral

Hi, I try to create a new project and add implementation in gradle

// Coil (Compose Image Loader library)
implementation("io.coil-kt:coil-compose:2.2.2")
implementation("net.engawapg.lib:zoomable:1.5.1")

the IDE show error message as below:

Failed to resolve: net.engawapg.lib:zoomable:1.5.1

I also try 1.5.0 and got the same error. Should I check anything for use it?


update: Seems my network issue, already fix it.

Enable zoom

Ability to enable/disable zoom would be really nice

detects wrong taps on zoomable LazyList when scrolling

@Composable
fun ZoomableLazyColumn() {
    LazyColumn(
        modifier = Modifier
            .fillMaxSize()
            .zoomable(
                rememberZoomState(),
                onTap = {
                    Log.d(TAG, "Tap")
                }
            )
    ) {
        items(50) {
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(100.dp)
            )
        }
    }
}

Question about Feasibility: Implementing Swipe-to-Dismiss Gesture for Full-Screen Image Viewer

First and foremost, I want to express my gratitude for the wonderful library you have created. The feature that allows zooming directly to the pinch location instead of the center of the image is something I have been seeking for a long time, and I truly appreciate it.

I have a question regarding the feasibility of a particular enhancement: I am utilizing your library to develop a full-screen image viewer for an application, and I am interested in incorporating the ability to dismiss the image by swiping it down when it is not zoomed. Essentially, I would like to replicate the behavior seen in Google Photos.

My image viewer will be a dedicated compose destination, which may limit the extent to which I can implement intricate animations like those in Google Photos, where the image shrinks and reposition itself on top of the grid. However, I would be content with a swipe-down animation causing the image to exit the screen and subsequently triggering a "navigate back" action on the NavHostController. My main concern is whether implementing this swipe gesture might interfere with the library's existing gestures. It's important to note that I only require this gesture to be active when the image is not zoomed, so there should be no conflict with the library's gestures at that particular moment.

Do you think that could be easily implemented or does it sound like something complex to build on top of this library?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.