Skip to content

#5976 Fix UI getting stuck when transition animation is interrupted #6000

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

ChronicLynx
Copy link
Contributor

@ChronicLynx ChronicLynx commented Mar 7, 2025

First time contributor checklist

Contributor checklist

  • My commits are rebased on the latest main branch
  • My commits are in nice logical chunks
  • My contribution is fully baked and is ready to be merged as is
  • I have tested my contribution on these devices:
  • iPhone 16 Pro (iOS 18.2, Xcode Simulator)

Description

This is a continuation of the issue in #5976. I encountered two scenarios over the week where after tapping done or cancel the buttons animated away, but the view failed to dismiss. I believe #5977 fixed part of this issue, as I haven't had the same error logged, but it's still possible via this route which doesn't generate an error. I think the frequency at which this occurs on my device is much less than pre-#5977 at least.

The theory here is that the animation is interrupted partway through the cycle and returns false even though the buttons have already been dismissed. I think these problems in general are indicative of a larger issue, but we may be able to provide relief by restoring the controls in the event of a cancelled animation.

Now, if iOS interrupts an animation, the controls are restored and the user can retry the operation. I was thinking about taking the business logic outside of the animation, but it degraded the UX of the crop tool by removing the smooth transitions.

Without this fix the user must force close the app to recover due to the controls being hidden, which is not ideal.

if animated {
            
            UIView.animate(withDuration: animationDuration,
                           animations: {
                self.updateControlsVisibility(hidden: hideControls)
                self.constrainContent(to: layoutGuide)
                self.updateImageViewTransform()
                // Animate layout changes made within bottomBar.setControls(hidden:).
                self.view.setNeedsDisplay()
                self.view.layoutIfNeeded()
            },
                           completion: completion)
        } else {
            updateControlsVisibility(hidden: hideControls)
            constrainContent(to: layoutGuide)
            updateImageViewTransform()
            completion?(true)
        }
    }
@objc
    private func didTapCancel() {
        transitionUI(toState: .initial, animated: true) { finished in
            
            // Fallback to reveal controls in case of an animation interruption
            guard finished else {
                    self.updateControlsVisibility(hidden: false)
                    self.imageView.layer.cornerRadius = 0
                    self.didTapReset()
                    return
                }
            self.dismiss(animated: false)
        }
    }

    @objc
    private func didTapDone() {
        model.replace(transform: transform)
        transitionUI(toState: .initial, animated: true) { finished in
            
            // Fallback to reveal controls in case of an animation interruption
            guard finished else {
                    self.updateControlsVisibility(hidden: false)
                    self.imageView.layer.cornerRadius = 0
                    self.didTapReset()
                    return
                }
            self.dismiss(animated: false)
        }
    }

Testing and Findings

I added self.didTapReset() to the guard statement because depending on where the animation is interrupted either self.constrainContent(to: layoutGuide) or self.updateImageViewTransform() could have been executed. Not calling reset works, but there's a moment where the user is left with an unrealistic portrayal of their crop which only corrects itself after tapping done again and rerunning the code block. To avoid this confusion I think it's best we just reset the crop tool in the event of the issue and let the user reattempt from scratch.

Demos with simulated animation interrupt:

DEMO: Functionality without Reset - YouTube

DEMO: Functionality with Reset - YouTube

Update: I realized, after posting the video, that the image corners were still round after reset since part of the transitionUI function had executed before the simulated error. Added another commit to reset the image corners inside of the guard statement and tested locally.

@ChronicLynx ChronicLynx changed the title Fix UI getting stuck when transition animation is interrupted #5976 Fix UI getting stuck when transition animation is interrupted Mar 8, 2025
Copy link

github-actions bot commented Jun 6, 2025

This PR has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@github-actions github-actions bot added the stale label Jun 6, 2025
@ChronicLynx
Copy link
Contributor Author

@sashaweiss-signal any thoughts on this? Low priority I'm sure, but it would be good to have a handler of some sort since it just hangs currently.

@github-actions github-actions bot removed the stale label Jun 13, 2025
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

Successfully merging this pull request may close these issues.

1 participant