I have a stateless page with a provider. I use Google AdMob to display ads (in_app_purchase
package).
On the page I have a start button. onPressed
event has below code to go to the next page:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const NextScreen()),
);
To implement rewarded ad I have added code to onPressed
event to detect whether the ads are required, and if so, instead of routing to the next page, a dialog box is displayed asking user to watch an ad. If the user accepts, this starts the ad process in the provider.
This all works great, but my problem is that when the reward is granted in the provider event, I do not know how to trigger the move to the next page.
The ad code in the provider class looks like this:
await _rewardedAd!.show(
onUserEarnedReward: (AdWithoutView ad, RewardItem reward) {
//here I can notify listeners to change the UI look, but not to trigger a page move
}
);
At that point I can notify listeners to change UI look, but not to trigger a page move. It would be useful to have some sort of a "function widget" that does nothing but listen for a value change and execute some code, but could not find such a thing.
At a time of desperation I even tried putting and invisible widget on the page to do that, but that triggers an error when I call navigator route from a widget that is being rebuilt.
It would be nice if button onPressed
even could listen for provider change, but I don't know if this is possible.
What is the proper way to do this? I suspect this is a very common scenario. Is this even possible to achieve with a stateless
widget and provider pattern? Must I switch to a stateful
widget?
Ended up implementing this solution which works but seems a bit hacky and not sure if it will cause some problems with the widget tree.
Will accept a better solution.
In a nutshell, provider has a special trigger variable that now a StateFulWidget
screen listens for in didChangeDependencies
event.
In the provider I have this code to display the ad and listen for rewarded event:
await _rewardedAd!.setImmersiveMode(true);
await _rewardedAd!.show(
onUserEarnedReward: (AdWithoutView ad, RewardItem reward) {
//set the trigger and notify listeners
_startWorkoutTrigger = true;
notifyListeners();
});
I converted the page to a StatefulWidget
and added this code to didChangeDependencies
event:
@override
Future<void> didChangeDependencies() async {
super.didChangeDependencies();
if (Provider.of<Settings>(context, listen: false)
.getStartTrigger()) {
Provider.of<Settings>(context, listen: false).cancelStartTrigger();
Future.delayed(
Duration.zero,
() => Navigator.push(
context,
MaterialPageRoute(builder: (context) => const NextScreen()),
));
}
}