Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zoomable modifier looses state after ZoomableState gets disposed and recreated #72

Closed
CalamityDeadshot opened this issue Mar 4, 2024 · 12 comments

Comments

@CalamityDeadshot
Copy link

I'm using Modifier.zoomable inside a HorizontalPager - a pretty standard use case.
My issue is that after a page is composed for a second time RealZoomableState looses its gestureState synchronization for some reason, so when ZoomableNode's onTransformStopped calls state.isZoomOutsideRange() its val userZoomFactor = gestureState?.userZoomFactor pretty much equals 1 for me, so state.smoothlySettleZoomOnGestureEnd() is not called whatsoever, and no zoom bounds are enforced.
A minimal repro with coil:

HorizontalPager(
    modifier = Modifier.fillMaxSize(),
    state = rememberPagerState(
        pageCount = { contents.size }
    ),
    beyondBoundsPageCount = 1
) { page ->
    val content = contents[page]
    val painter = rememberAsyncImagePainter(content.url)
    val zoomableState = rememberZoomableState(
        zoomSpec = ZoomSpec(
            maxZoomFactor = 3f,
            preventOverOrUnderZoom = false
        )
    )
    LaunchedEffect(painter.intrinsicSize) {
        if (painter.intrinsicSize.isSpecified) {
            zoomableState.setContentLocation(
                ZoomableContentLocation.scaledToFitAndCenterAligned(painter.intrinsicSize)
            )
        }
    }
    val contentModifier = Modifier
        .fillMaxSize()
        .zoomable(
            state = zoomableState
        )
    Image(
        painter = painter,
        contentDescription = null,
        contentScale = ContentScale.Fit,
        modifier = contentModifier,
    )
}

Here's how it looks for users:

video5417946174109795186.mp4

The same thing happens with pages that are composed for the first time if I scroll enough pages forwards/backwards from initialPage. Is my usage incorrect in some way?

Versions:

    kotlinCompilerExtensionVersion = "1.5.1"

    implementation(platform("androidx.compose:compose-bom:2024.02.00")) // So, androidx.compose.foundation:foundation is 1.6.2
    implementation("io.coil-kt:coil-compose:2.1.0")
    implementation("me.saket.telephoto:zoomable:0.8.0")
@CalamityDeadshot
Copy link
Author

CalamityDeadshot commented Mar 4, 2024

Also, flings no longer work in this situation either

@saket
Copy link
Owner

saket commented Mar 5, 2024

Is this no longer an issue?

@CalamityDeadshot
Copy link
Author

It is. I honestly don't know why it's closed. I don't remember closing it. Maybe a missclick

@CalamityDeadshot
Copy link
Author

Ah, I see. I referenced this issue in a commit to a private repo with a message containing Still need to fix https://github.com/saket/telephoto/issues/72. I guess GitHub tried to be clever. Funny

@kvn-stgl
Copy link

kvn-stgl commented Mar 6, 2024

I think I have the same problem with the SubSamplingImage (with the ZoomableAsyncImage everything works as expected, sadly I can't use it for reasons).

I've changed the sample app a bit to reproduce the issue: kvn-stgl@b1b74ac
You only have to swipe the pager forward and backward. After the backward swipe, the double tab and back fling do not work anymore. Only the multitouch zoom.

Here is also a short video:

Screen_recording_20240306_105618.mp4

@saket
Copy link
Owner

saket commented Mar 16, 2024

@kvn-stgl I was able to reproduce the problem using your sample, thank you! This is related to #70.

@kvn-stgl and @CalamityDeadshot I'm also curious to learn your reasons for not using ZoomableAsyncImage(). Are both of you writing a multiplatform app?

@saket
Copy link
Owner

saket commented Mar 16, 2024

1749177 was deployed to maven. Can you please try out 0.9.0-SNAPSHOT?

@CalamityDeadshot
Copy link
Author

reasons for not using ZoomableAsyncImage()

My gallery displays multiple types of content, like photos and videos, so it just makes more sense to use Modifier.zoomable for different types of content rather than implement a different solution for each one.

@CalamityDeadshot
Copy link
Author

Can you please try out 0.9.0-SNAPSHOT?

I no longer experience this issue with me.saket.telephoto:zoomable:0.9.0-SNAPSHOT. Thank you for a quick fix!

@saket
Copy link
Owner

saket commented Mar 16, 2024

@CalamityDeadshot glad to hear!

My gallery displays multiple types of content, like photos and videos, so it just makes more sense to use Modifier.zoomable for different types of content rather than implement a different solution for each one.

This is exactly the usecase I wanted to support with having a decoupled ZoomableState. You shouldn't need to touch the lower level APIs for sharing your zoomable code between images and videos:

val zoomableState = rememberZoomableState()

when (media) {
 is Image -> {
    ZoomableAsyncImage(
     model = media.imageUrl,
     state = rememberZoomableImageState(zoomableState),
    )
  }
  is Video -> {
    ZoomableVideoPlayer(
      model = media.videoUrl,
      state = rememberZoomableExoState(zoomableState),
    )
  }
}

I'm going ahead and closing this issue, but let's continue this discussion because I want to nudge developers away from maintaining their own implementation of ZoomableAsyncImage().

@saket saket closed this as completed Mar 16, 2024
@CalamityDeadshot
Copy link
Author

You shouldn't need to touch the lower level APIs for sharing your zoomable code between images and videos

It's more of a matter of interoperability for me, as my gallery uses Painters as models for images and generic composable content models for videos.

val contentModifier = Modifier
    .fillMaxSize()
    .zoomable(
        state = zoomableState,
        onClick = { onClick() }
    )
when (model) {
    is Painter -> {
        // ...
        Image(
            painter = model,
            contentDescription = null,
            contentScale = ContentScale.Fit,
            modifier = contentModifier,
        )
    }
    is ComposeModel -> {
        // ...
        Box(
            modifier = contentModifier,
            contentAlignment = Alignment.Center
        ) {
            model.content()
        }
    }
}

This comes from a fork of this gallery which had its own transform gestures implementation, but it broke horribly (with a fatal crash) after I updated androidx.compose.foundation:foundation version to gain access to essential new features. It happened at such an unfortunate time, too - release deadline is around the corner, and I could not spare time to find the bug and fix it (this lib's code is, um... hard to reason about). I'm lucky I found Telephoto :)
So, basically, you are probably right, but I don't have the resources to refactor this at the moment, as this gallery API is currently used all over the app, - but I most certainly intend to! Sub-sampling alone is a very cool feature.

@saket
Copy link
Owner

saket commented Mar 25, 2024

Got it. Thanks for explaining!

github-merge-queue bot pushed a commit to slackhq/circuit that referenced this issue Mar 26, 2024
…1308)

This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[me.saket.telephoto:zoomable-image-coil](https://togithub.com/saket/telephoto)
| dependencies | minor | `0.8.0` -> `0.9.0` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the Dependency
Dashboard for more information.

---

### Release Notes

<details>
<summary>saket/telephoto
(me.saket.telephoto:zoomable-image-coil)</summary>

### [`v0.9.0`](https://togithub.com/saket/telephoto/releases/tag/0.9.0)

[Compare
Source](https://togithub.com/saket/telephoto/compare/0.8.0...0.9.0)

Bug fixes

-
[saket/telephoto#70,
[saket/telephoto#72:
Zoomable modifier looses state after ZoomableState gets disposed and
recreated

Dependency updates

-   Compose compiler: 1.5.10
-   Compose UI: 1.6.3
-   Compose multiplatform: 1.6.1

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Renovate
Bot](https://togithub.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4yNzAuMCIsInVwZGF0ZWRJblZlciI6IjM3LjI3MC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiJ9-->
github-merge-queue bot pushed a commit to slackhq/circuit that referenced this issue Mar 26, 2024
…1308)

This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[me.saket.telephoto:zoomable-image-coil](https://togithub.com/saket/telephoto)
| dependencies | minor | `0.8.0` -> `0.9.0` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the Dependency
Dashboard for more information.

---

### Release Notes

<details>
<summary>saket/telephoto
(me.saket.telephoto:zoomable-image-coil)</summary>

### [`v0.9.0`](https://togithub.com/saket/telephoto/releases/tag/0.9.0)

[Compare
Source](https://togithub.com/saket/telephoto/compare/0.8.0...0.9.0)

Bug fixes

-
[saket/telephoto#70,
[saket/telephoto#72:
Zoomable modifier looses state after ZoomableState gets disposed and
recreated

Dependency updates

-   Compose compiler: 1.5.10
-   Compose UI: 1.6.3
-   Compose multiplatform: 1.6.1

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Renovate
Bot](https://togithub.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4yNzAuMCIsInVwZGF0ZWRJblZlciI6IjM3LjI3MC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiJ9-->
ZacSweers pushed a commit to ZacSweers/CatchUp that referenced this issue Mar 27, 2024
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
|
[me.saket.telephoto:zoomable-image-coil](https://togithub.com/saket/telephoto)
| `0.8.0` -> `0.9.0` |
[![age](https://developer.mend.io/api/mc/badges/age/maven/me.saket.telephoto:zoomable-image-coil/0.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/maven/me.saket.telephoto:zoomable-image-coil/0.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/maven/me.saket.telephoto:zoomable-image-coil/0.8.0/0.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/me.saket.telephoto:zoomable-image-coil/0.8.0/0.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
|
[me.saket.telephoto:zoomable-image](https://togithub.com/saket/telephoto)
| `0.8.0` -> `0.9.0` |
[![age](https://developer.mend.io/api/mc/badges/age/maven/me.saket.telephoto:zoomable-image/0.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/maven/me.saket.telephoto:zoomable-image/0.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/maven/me.saket.telephoto:zoomable-image/0.8.0/0.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/me.saket.telephoto:zoomable-image/0.8.0/0.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [me.saket.telephoto:zoomable](https://togithub.com/saket/telephoto) |
`0.8.0` -> `0.9.0` |
[![age](https://developer.mend.io/api/mc/badges/age/maven/me.saket.telephoto:zoomable/0.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/maven/me.saket.telephoto:zoomable/0.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/maven/me.saket.telephoto:zoomable/0.8.0/0.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/me.saket.telephoto:zoomable/0.8.0/0.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>saket/telephoto
(me.saket.telephoto:zoomable-image-coil)</summary>

### [`v0.9.0`](https://togithub.com/saket/telephoto/releases/tag/0.9.0)

[Compare
Source](https://togithub.com/saket/telephoto/compare/0.8.0...0.9.0)

Bug fixes

-
[saket/telephoto#70,
[saket/telephoto#72:
Zoomable modifier looses state after ZoomableState gets disposed and
recreated

Dependency updates

-   Compose compiler: 1.5.10
-   Compose UI: 1.6.3
-   Compose multiplatform: 1.6.1

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these
updates again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/ZacSweers/CatchUp).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4yNjkuMiIsInVwZGF0ZWRJblZlciI6IjM3LjI2OS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiJ9-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
ZacSweers pushed a commit to ZacSweers/CatchUp that referenced this issue Apr 15, 2024
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
|
[me.saket.telephoto:zoomable-image-coil](https://togithub.com/saket/telephoto)
| `0.9.0` -> `0.10.0` |
[![age](https://developer.mend.io/api/mc/badges/age/maven/me.saket.telephoto:zoomable-image-coil/0.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/maven/me.saket.telephoto:zoomable-image-coil/0.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/maven/me.saket.telephoto:zoomable-image-coil/0.9.0/0.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/me.saket.telephoto:zoomable-image-coil/0.9.0/0.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
|
[me.saket.telephoto:zoomable-image](https://togithub.com/saket/telephoto)
| `0.9.0` -> `0.10.0` |
[![age](https://developer.mend.io/api/mc/badges/age/maven/me.saket.telephoto:zoomable-image/0.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/maven/me.saket.telephoto:zoomable-image/0.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/maven/me.saket.telephoto:zoomable-image/0.9.0/0.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/me.saket.telephoto:zoomable-image/0.9.0/0.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
| [me.saket.telephoto:zoomable](https://togithub.com/saket/telephoto) |
`0.9.0` -> `0.10.0` |
[![age](https://developer.mend.io/api/mc/badges/age/maven/me.saket.telephoto:zoomable/0.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/maven/me.saket.telephoto:zoomable/0.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/maven/me.saket.telephoto:zoomable/0.9.0/0.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/me.saket.telephoto:zoomable/0.9.0/0.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>saket/telephoto
(me.saket.telephoto:zoomable-image-coil)</summary>

###
[`v0.10.0`](https://togithub.com/saket/telephoto/releases/tag/0.10.0)

[Compare
Source](https://togithub.com/saket/telephoto/compare/0.9.0...0.10.0)

Bug fixes

-
[saket/telephoto#70,
[saket/telephoto#72:
Correctly update `ZoomableState` when `Modifier.zoomable()` is reused
-
[saket/telephoto#71:
Make sure velocity tracker tracks the same pointer
-
[saket/telephoto#81:
Read maximum fling velocity from composition locals

Dependency updates

-   Compose compiler: 1.5.11
-   Compose UI: 1.6.4
-   Compose multiplatform: 1.6.4

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these
updates again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/ZacSweers/CatchUp).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4yOTMuMCIsInVwZGF0ZWRJblZlciI6IjM3LjI5My4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
github-merge-queue bot pushed a commit to slackhq/circuit that referenced this issue Apr 16, 2024
…1339)

This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[me.saket.telephoto:zoomable-image-coil](https://togithub.com/saket/telephoto)
| dependencies | minor | `0.9.0` -> `0.10.0` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the Dependency
Dashboard for more information.

---

### Release Notes

<details>
<summary>saket/telephoto
(me.saket.telephoto:zoomable-image-coil)</summary>

###
[`v0.10.0`](https://togithub.com/saket/telephoto/releases/tag/0.10.0)

[Compare
Source](https://togithub.com/saket/telephoto/compare/0.9.0...0.10.0)

Bug fixes

-
[saket/telephoto#70,
[saket/telephoto#72:
Correctly update `ZoomableState` when `Modifier.zoomable()` is reused
-
[saket/telephoto#71:
Make sure velocity tracker tracks the same pointer
-
[saket/telephoto#81:
Read maximum fling velocity from composition locals

Dependency updates

-   Compose compiler: 1.5.11
-   Compose UI: 1.6.4
-   Compose multiplatform: 1.6.4

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Renovate
Bot](https://togithub.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4yOTYuMCIsInVwZGF0ZWRJblZlciI6IjM3LjI5Ni4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants