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

feat: need a way of knowing when swipe to go back is aborted #28929

Open
3 tasks done
lincolnthree opened this issue Jan 30, 2024 · 18 comments
Open
3 tasks done

feat: need a way of knowing when swipe to go back is aborted #28929

lincolnthree opened this issue Jan 30, 2024 · 18 comments
Labels
package: core @ionic/core package type: feature request a new feature, enhancement, or improvement

Comments

@lincolnthree
Copy link

Prerequisites

Describe the Feature Request

Currently we have four primary `ionView[Did/Will][Enter/Leave] events to observe during navigation & animation. However, there are scenarios where these events may be fired, but the user cancels the action and stays on the current screen. There does not seem to be a way to detect this scenario, unless I am missing something.

Existing events: https://ionicframework.com/docs/angular/lifecycle

I would like to be able to observe ionViewDidNotEnter and ionViewDidNotLeave events (or something to that effect), so that we can understand when users started to leave the page, but did not.

Describe the Use Case

On iOS, as an example, a user swipes right to go back to the previous page, then decides to stay on the page they're looking at. However, ionViewWillLeave has been called, and the current page has taken some action that needs to be rolled back when the animation finishes. For the sake of this use case, it is not possible to use the ionViewDidLeave event for what the page needs to do.

Unless I've missed a feature or event to observe, we need supplemental events to know when this situation occurs.

Describe Preferred Solution

Publish ionViewDidNotEnter and ionViewDidNotLeave events to supplement the existing ones we already have.

Describe Alternatives

Not sure.

Related Code

No response

Additional Information

No response

@liamdebeasi
Copy link
Contributor

Thanks for the report. Does using ionViewDidLeave work for your use case? Your use case describes needing to roll back an action that happens on ionViewWillLeave. However, if you perform that action in ionViewDidLeave you remove the need to ever roll the action back because the user confirmed their navigation away from the page.

@liamdebeasi liamdebeasi added the needs: reply the issue needs a response from the user label Jan 31, 2024
@ionitron-bot ionitron-bot bot removed the triage label Jan 31, 2024
@lincolnthree
Copy link
Author

lincolnthree commented Jan 31, 2024

Hey @liamdebeasi, unfortunately as stated in the description, this is not possible. It technically works but creates a situation for us where the user can momentarily see & interact with elements that need to be gone by the time the animation is started, but need to be restored when he gesture is aborted. We use Angular content portals to project content dynamically and it needs to be in the right place at the right time.

@ionitron-bot ionitron-bot bot added triage and removed needs: reply the issue needs a response from the user labels Jan 31, 2024
@liamdebeasi
Copy link
Contributor

Do you have an example of the elements that you need removed in your application?

@liamdebeasi liamdebeasi added the needs: reply the issue needs a response from the user label Feb 1, 2024
@ionitron-bot ionitron-bot bot removed the triage label Feb 1, 2024
@aeharding
Copy link
Contributor

Huh, weird timing! I was also just experiencing trouble with the lack of published events for this scenario. Below is my use case:

  • In my case, I have a singleton <video> element that I portal around the application so that playback is not interrupted. I use react-reverse-portal to accomplish this.
  • Observe video is pulled/pushed from pages as expected, listening to ionViewWillEnter event to "pull" the <video> element into the correct place.
  • Observe at the end of the video, instead of fully swiping back, I stop swiping, and the page transition never completes.
  • There is no event to catch this case. willEnter/didEnter/willLeave/didLeave do not get called. I don't know if this is a bug (perhaps willEnter and didEnter should be re-called if you don't complete the swipe back?), or as per OP, perhaps new ionViewDidNotEnter and ionViewDidNotLeave events should be published. Either of these solutions would work for my case.

If it helps, I would be happy to create a reproduction. But essentially, there are no Ionic events published to detect the situation where a swipe back does not fully complete.

Kapture.2024-02-04.at.14.49.52.mp4

@ionitron-bot ionitron-bot bot added triage and removed needs: reply the issue needs a response from the user labels Feb 4, 2024
aeharding added a commit to aeharding/voyager that referenced this issue Feb 4, 2024
@lincolnthree
Copy link
Author

@aeharding Yes! This is almost exactly our scenario. Thanks for posting! Love the timing :D

@liamdebeasi
Copy link
Contributor

liamdebeasi commented Feb 5, 2024

Would an IntersectionObserver work for the video use case? Unless the video sticks to the top of the screen as you scroll, I imagine you would want to pause the video when the video scrolls out of the viewport as well. Using IntersectionObserver would let you cover both cases.

@liamdebeasi liamdebeasi added the needs: reply the issue needs a response from the user label Feb 5, 2024
@ionitron-bot ionitron-bot bot removed the triage label Feb 5, 2024
@aeharding
Copy link
Contributor

Would an IntersectionObserver work for the video use case? Unless the video sticks to the top of the screen as you scroll, I imagine you would want to pause the video when the video scrolls out of the viewport as well. Using IntersectionObserver would let you cover both cases.

I already use Intersection Observer for your mentioned case of play/pause while scrolling feed, but it is not well suited for detecting page navigations in my testing.

  1. I want to change video element location before the page animation starts to avoid stutters.
  2. Furthermore using an Intersection Observer for that introduces other unavoidable edge cases, due to the fact that you cannot discern the difference between page navigation intersections and feed scroll intersections. For example say trigger point = 50% or whatever. If you change pages while the video on the page you're navigating to is 40% scrolled off the feed, it does not fire. Unless you set the intersection observer to fire when 0.00001% of the element is visible, which has the same problem as this original issue (won't fire if you start swiping back, then don't fully swipe back.)

There's a few other DevEx reasons (there is a lot of extra code, and I need to use 2x the intersection observers due to reverse portals), but they're not blockers like the above.


Side note, on https://ionicframework.com/docs/angular/lifecycle it says,

ionViewWillLeave - Can be used for cleanup, like unsubscribing from observables.

But, I don't think this is a good advice due to the original issue. If you were to cleanup observables on ionViewWillLeave but then you don't actually complete the swipe back, your application on that page would be in a broken state, right?

@ionitron-bot ionitron-bot bot added triage and removed needs: reply the issue needs a response from the user labels Feb 5, 2024
@liamdebeasi
Copy link
Contributor

Furthermore using an Intersection Observer for that introduces other unavoidable edge cases, due to the fact that you cannot discern the difference between page navigation intersections and feed scroll intersections. For example say trigger point = 50% or whatever. If you change pages while the video on the page you're navigating to is 40% scrolled off the feed, it does not fire. Unless you set the intersection observer to fire when 0.00001% of the element is visible, which has the same problem as this original issue (won't fire if you start swiping back, then don't fully swipe back.)

Do you have an example of this issue that I can look at?


Native iOS doesn't have a standard way of detecting when a swipe gesture is cancelled, so it's possible there's another approach here that would solve the problem.

@liamdebeasi liamdebeasi added the needs: reply the issue needs a response from the user label Feb 6, 2024
@ionitron-bot ionitron-bot bot removed the triage label Feb 6, 2024
@aeharding
Copy link
Contributor

Do you have an example of this issue that I can look at?

I can get you a repro example if it would help, but it may take a bit to set up. :)


Native iOS doesn't have a standard way of detecting when a swipe gesture is cancelled, so it's possible there's another approach here that would solve the problem.

This is interesting that you mentioned, so I decided to look and see what native iOS does. It turns out that native iOS re-triggers lifecycle events when you do not complete a swipe back. Please see the following Youtube video (linking to around 9:30):

https://youtu.be/wLS26PfQeAs?si=ZBBQ_irI444i24gm&t=562

As you can see, when he lifts his finger (and swipe back does not complete), the following lifecycle events in yellow are triggered. This is different than Ionic, which does not trigger any lifecycle events when you cancel the swipe back.

image

@ionitron-bot ionitron-bot bot added triage and removed needs: reply the issue needs a response from the user labels Feb 6, 2024
@liamdebeasi
Copy link
Contributor

Ah that's interesting. If the will/did events fired when cancelling the swipe gesture would that make it easier to implement the pattern you described above?

@aeharding
Copy link
Contributor

Ah that's interesting. If the will/did events fired when cancelling the swipe gesture would that make it easier to implement the pattern you described above?

I can't speak for @lincolnthree, but firing those extra will/did events would fully address my edge case!

@lincolnthree
Copy link
Author

lincolnthree commented Feb 6, 2024

Ah that's interesting. If the will/did events fired when cancelling the swipe gesture would that make it easier to implement the pattern you described above?

Yes 100%. Though it would be a potentially breaking change for many apps rather than a new feature. You'd have to review all of your existing event handlers and make sure nothing bad happens if they are called multiple times. That's why I opted to suggest the introduction of a new API rather than overload the existing one, but I can see it going both ways if you want to keep things minimal. It just means apps will break.

Additionally, while it would solve this specific case, there is some nuance to using separate events. E.g. the nature of the event is unknown if you call the same event handlers. You could do some complex state checking I guess, to determine what situation the DidEnter handler is being called in (e.g.: first time means page loaded, second+ time means page leave started and aborted, but only if WillLeave was called first).

@liamdebeasi
Copy link
Contributor

liamdebeasi commented Feb 6, 2024

Thanks! There's some research we need to do as to what the best way of implementing this is. At the very least, the uses cases described here should be achievable within Ionic Framework so we should try and find a resolution.

@liamdebeasi liamdebeasi changed the title feat: publish ionViewDidNotEnter & ionViewDidNotLeave events feat: need a way of knowing when swipe to go back is aborted Feb 6, 2024
@liamdebeasi liamdebeasi added type: feature request a new feature, enhancement, or improvement package: core @ionic/core package labels Feb 6, 2024
@liamdebeasi liamdebeasi removed their assignment Feb 6, 2024
@ionitron-bot ionitron-bot bot removed the triage label Feb 6, 2024
@lincolnthree
Copy link
Author

Thanks! There's some research we need to do as to what the best way of implementing this is. At the very least, the uses cases described here should be achievable within Ionic Framework so we should try and find a resolution.

Awesome! Glad we could help, and looking forward to doing even more fancy things with Ionic :D Do you know of any "secret" hooks / hacks we could tie into in the mean time? Anything we could overload or override?

aeharding added a commit to aeharding/voyager that referenced this issue Feb 8, 2024
Note: This has a problem documented below
ionic-team/ionic-framework#28929

Also implemented mute/unmute as well as playing paused videos (or autoplay disabled)

Player needs further optimization
@liamdebeasi
Copy link
Contributor

We do have a private swipeHandler API that we use in our routing integrations. This lets us know when to call router.back() or not:

@Prop() swipeHandler?: SwipeGestureHandler;

Your mileage may vary here, but that might be a possible workaround for now.

@lincolnthree
Copy link
Author

Wondering if any decisions have been made on this? We're still trying to figure out if we should wait, or try to hack in a workaround. Thanks!

@AE1NS
Copy link

AE1NS commented Jul 18, 2024

Same here. Would be really helpful to have ionViewDidLeave and ionViewDidEnter triggered for the corresponding pages, when the swipe action is aborted, to have a consistent state in the end.

@AE1NS
Copy link

AE1NS commented Jul 18, 2024

const swipeHandler = (this._navController as any).topOutlet.nativeEl.swipeHandler;
(this._navController as any).topOutlet.nativeEl.swipeHandler = {
    canStart: () => {
        console.log('canStart');
        return swipeHandler.canStart();
    },
    onStart: () => {
        console.log('onStart');
        return swipeHandler.onStart();
    },
    onEnd: (shouldContinue) => {
        console.log('onEnd');
        return swipeHandler.onEnd(shouldContinue);
    },
};

For now we can solve our issues with the help of the swipeHandler. Thank you for the hint @liamdebeasi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package: core @ionic/core package type: feature request a new feature, enhancement, or improvement
Projects
None yet
Development

No branches or pull requests

4 participants