slovnicki / beamer

A routing package built on top of Router and Navigator's pages API, supporting arbitrary nested navigation, guards and more.
MIT License
592 stars 129 forks source link

Wait for Disposal when Beaming to same Detail Screen #543

Open rivella50 opened 2 years ago

rivella50 commented 2 years ago

Is your feature request related to a problem? Please describe. One of my screens lists contracts and allows to click and beam to the corresponding details screen:

onTap: () {
   context.beamToNamed('/contracts/${contract.id}');
},

My app also allows receiving FCM messages and beam directly to a contract details page (independent of where the user currently is), which works fine if the currently visited page isn't a contract details page as well (with a different contract id). The problem then is that one stream listener within the details page may not occur twice at the same time, and since building the new contract details page seems to happen before disposing the old one (i've checked that with print statements) the new page doesn't render/work correctly. If i use this hack it works (i.e. leaving the current details page, wait 1 second and only then beam to the new details page):

_beamerDelegate.beamToNamed('/contracts');
Future<dynamic>.delayed(const Duration(seconds: 1)).then((dynamic value) =>
    _beamerDelegate.beamToNamed('/contracts/${contract.id}')
);

During the delay time the old details page is disposed (which includes the stream provider). Of course this is a very ugly workaround.

Describe the solution you'd like Far better would be having the possibility to define an option (e.g. a boolean) that the disposal should be awaited until the new page starts building - if old and new paths are the same and only differ in a path parameter (here: the contract id).

If there is already an option or a way to accomplish that please let me know. Everything is better than my hack ;-) Else i would like to see this as a feature request and i am eager to hear what you think about it.

slovnicki commented 2 years ago

Hey @rivella50 :wave: Thanks for creating an issue and sorry for a late response.

This seems to be related to TransitionDelegate. How does your app behave if you try to override it either

rivella50 commented 2 years ago

@slovnicki Doesn't change anything, unfortunately. It still seems that the former details page has not been completely disposed before the new details page enters the scene - and therefore blocks listening to that one stream provider.

The question is: If i write my own TransitionDelegate extension would i have a chance to check the disposal state of the former details page?

rivella50 commented 2 years ago

@slovnicki I could solve it somehow meanwhile by forcing the mentioned stream provider to dispose before the listener is registered again. What came into my mind: How about adding some sort of hook that could be used between a page change invoked by beamToNamed?

Example: Consider the user is on page /contracts/A Now an incoming FCM message calls for navigating to page /contracts/B which is done by using beamToNamed(...). In order to accomplish that page change Beamer would probably have to pop page A and push page B (i.e. 2 steps). My idea is to have a hook method available which would be invoked after page A has been popped and before page B is pushed. Within that hook method i could invalidate (i.e. dispose) the stream provider which caused the problems. Params of that hook method could be currentBeamLocation and targetBeamLocation. With these params i could determine if it's necessary to invalidate the stream provider (e.g. if the user's current location is /tickets the disposal wouldn't be necessary).

I don't know if that makes sense, but i'm curious what you thank about this suggestion.

rivella50 commented 2 years ago

@slovnicki Forget my last post. I just figured out that a hook would be way more suitable after beamToNamed has finished its work, i.e. if navigating to page /contracts/B has been performed. With that a call could look like this: _beamerDelegate.beamToNamed( 'contracts/B', transitionDelegate: const NoAnimationTransitionDelegate(), onFinishBeam: (targetBeamLocation) => print('beam finished'), );

slovnicki commented 2 years ago

@rivella50 This seems like a very useful feature. Have you tried something like this?

If this works, we could try adding listeners and/or notifiers at BeamPage.createRoute and then try to redirect the result into onFinishBeam as you suggest. Seems like a good API to have, although I'm not sure at the moment what will be the exact approach to implementing it.

Let me know about the solution from the link above :pray:

rivella50 commented 2 years ago

@slovnicki The question is if router.animation does also give information even when i'm using NoAnimationTransitionDelegate? I've quickly tried this in my project and didn't get a status printed on entering the target page, but only when leaving it these two: AnimationStatus.reverse, AnimationStatus.dismissed.

slovnicki commented 2 years ago

@rivella50 I see... I'll check out what's happening inside the Flutter code for this and try to explore some other solutions too. Feel free to post your research here if you will be doing any.

rivella50 commented 2 years ago

@slovnicki I'm not sure if the animation is relevant at all here. When the transition animation (if defined) to the new page starts hasn't the target page already finished rendering? If that's the case then the AnimationStatus wouldn't be needed to invoke onFinishBeam.