Flutter app not showing ads after closing and opening - flutter

I only use interstitial in the app. An interstitial ad appears on the first click on app launch, and it takes 15 clicks for the ad to appear again.
The problem is that when I exit the app and re-enter after a while, it doesn't show ads on the first click. In fact, sometimes the problem of not showing ads on the first click takes a few days. But after 15 clicks it shows ads.
What I want to do is show an ad on the first click of users every time they enter the app. I'm not sure if this is a bug or something with the code.
PS: I am using getx state management - The ad impression limit is limited to 5 times a day per user.
Interstitial ad controller:
class AdController extends GetxController {
InterstitialAd? interstitialAd;
int adCounter = 0;
int interstitialLoadAttempts = 0;
int maxAttempts = 3;
void onAdLoaded(InterstitialAd ad) {
interstitialAd = ad;
interstitialLoadAttempts = 0;
interstitialAd?.fullScreenContentCallback = FullScreenContentCallback(
onAdDismissedFullScreenContent: (ad) {
interstitialAd?.dispose();
initAd();
},
onAdFailedToShowFullScreenContent: (ad, error) {
interstitialAd?.dispose();
initAd();
},
);
}
void initAd() {
InterstitialAd.load(
adUnitId: AdHelper.interstitialAdUnitId,
request: const AdRequest(),
adLoadCallback: InterstitialAdLoadCallback(
onAdLoaded: onAdLoaded,
onAdFailedToLoad: (error) {
interstitialLoadAttempts++;
interstitialAd = null;
if (interstitialLoadAttempts <= maxAttempts) {
initAd();
}
},
),
);
}
void getAd() {
if (adCounter % 15 == 0 && interstitialAd != null) {
interstitialAd?.show();
interstitialAd = null;
}
adCounter++;
}
#override
void onInit() {
initAd();
super.onInit();
}
#override
void dispose() {
interstitialAd?.dispose();
super.dispose();
}
}
Ad display:
AdController AdController = Get.put(AdController());
return Padding(
padding: EdgeInsets.symmetric(
horizontal: 7.w,
vertical: 8.h, ),
child: GestureDetector(
onTap: () {
AdController.getAd();
Get.to( const ContentIndex(),
transition: Transition.native,
duration: const Duration(milliseconds: 250),
arguments: contentDex, );

Related

How to do Arithmetic operations (increment) on an int, which was a string initially

I have a flutter's ElevatedButton to show a rewardedAd. It shows a string:'show ad' initially. But after watching an ad, i want to display an int:'+10' inside it. Also, I want to increment +10 every time I click on it (watch an ad).
my code:
RewardedAd? _rewardedAd;
int _rewardedScore = 0;
#override
void initState() {
// TODO: implement initState
super.initState();
_createRewardedAd();
}
void _createRewardedAd() {
RewardedAd.load(
adUnitId: 'ca-app-pub-3940256099942544/5224354917',
request: AdRequest(),
rewardedAdLoadCallback: RewardedAdLoadCallback(
onAdLoaded: (RewardedAd ad) {
print('$ad loaded.');
// Keep a reference to the ad so you can show it later.
setState(() => this._rewardedAd = ad);
},
onAdFailedToLoad: (LoadAdError error) {
print('RewardedAd failed to load: $error');
setState(() {
_rewardedAd = null;
});
},
),
);
}
void _showRewardedAd() {
_rewardedAd?.fullScreenContentCallback = FullScreenContentCallback(
onAdShowedFullScreenContent: (RewardedAd ad) =>
print('$ad onAdShowedFullScreenContent.'),
onAdDismissedFullScreenContent: (RewardedAd ad) {
print('$ad onAdDismissedFullScreenContent.');
ad.dispose(); // dispose ad and
_createRewardedAd(); // then, create a new one
},
onAdFailedToShowFullScreenContent: (RewardedAd ad, AdError error) {
print('$ad onAdFailedToShowFullScreenContent: $error');
ad.dispose(); // dispose ad and
_createRewardedAd(); // then, create a new one
},
onAdImpression: (RewardedAd ad) => print('$ad impression occurred.'),
);
_rewardedAd?.show(
onUserEarnedReward: (AdWithoutView ad, RewardItem reward) {
setState(() {
_rewardedScore = _rewardedScore + 10;
});
});
_rewardedAd = null;
}
Scaffold(
appBar: AppBar(
title: Text('Rewarded: $_rewardedScore'),
centerTitle: true,
),
body: Center(
child: ElevatedButton(
child: Text(
"show ad",
style: TextStyle(fontSize: 30),
),
onPressed: () {
print('clicked rewarded');
_showRewardedAd();
},
),
),
);
You can either Text(reward.toString()) with int reward
Or (int.parse(reward)+10).toString() with string reward
"I figured it out! Time travel! I figured it out".
we go back to time, and bring back the Text() stones, and snap both string and int back back to reality.
make a bool variable.
bool clickedButton = false;
Then, use Ternary Operator to store one of these values:
either the int variable: +10 (if true)
or the string: "Show ad" (if false, as by default)
edit the Text() widget as:
Text(
clickedButton? '$_rewardedScore' : 'Show Ad',
style: TextStyle(fontSize: 30),
)
Make a nullable String type variable like
String? showAd;
and use it like
Text(showAd ?? "show ad");
For incrementing the value write a function like this
showAd = watchAd(showAd)
String watchAd(String? ad){
int _newValue = int.parse(ad ?? '0');
_newValue+=10;
return _newValue.toString();
}

Controller not updating UI in good time to display appropriate progress

In a personal flutter project am working with Getx state management whereby am fetching data from a parse server to then save it to my local db on the app. Everything works fine in the backend in terms of fetching the data and later saving it locally as you can see in my controller class below.
However once I get the data from the server I want to display my custom progress but the ui is frozed with the circular progress and when it unfreezes the activity that was to update the progress is done at 99%. Am using Drift a wrapper around Sqlite.
class ProgressController extends GetxController {
String classid = '';
int progressValue = 0;
List<Student>? students = [];
MyDatabase? db;
#override
void onInit() {
super.onInit();
}
#override
void onReady() {
super.onReady();
}
#override
void onClose() {
super.onClose();
}
/// Get the list of students from the server
Future<List<Student>?> fetchStudentsData() async {
bool isConnected = await hasReliableInternetConnectivity();
if (isConnected) {
final EventObject eventObject = await httpGet(
client: http.Client(),
url: '${ApiConstants.students}?where={"class":$classid}&order=studentid&limit=1000',
);
try {
if (eventObject.id == EventConstants.requestSuccessful) {
final StudentsResponse jsonResponse = StudentsResponse.fromJson(
json.decode(eventObject.response),
);
students = jsonResponse.results;
if (students!.isNotEmpty) {
saveStudentsData();
} else {
showToast(
text: "No data was found",
state: ToastStates.error,
);
}
}
} catch (exception) {
students = null;
}
} else {
showToast(
text: "You don't seem to have reliable internet connection",
state: ToastStates.error,
);
students = null;
}
update();
return students;
}
/// Save students data to the local db
Future<void> saveStudentsData() async {
for (int i = 0; i < students!.length; i++) {
int progress = (i / students!.length * 100).toInt();
if (progress > progressValue) {
progressValue = progress;
update();
}
db!.saveNewStudent(students![i]);
}
update();
Get.offAll(() => HomeView());
}
}
class ProgressView extends StatelessWidget {
final ProgressController controller = Get.put(ProgressController());
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
margin: const EdgeInsets.all(30),
child: GetBuilder<ProgressController>(
builder: (controller) => FutureBuilder<List<Student>?>(
future: controller.fetchStudentsData(),
builder: (BuildContext context,
AsyncSnapshot<List<Student>?> snapshot) {
if (snapshot.hasData) {
if (snapshot.data!.isNotEmpty) {
return LineProgress(
progressSize: 100,
progressVl: controller.progressValue,
borderColor: Colors.black,
progressColor: AppColors.primaryColor,
backgroundColor: AppColors.secondaryColor,
);
} else {
return const Text('You are not connected to the internet');
}
} else if (snapshot.hasError) {
return const Text('An unexpected error occured');
} else {
return const CircularProgress();
}
},
),
),
),
),
);
}
}
My ui in the save view is as shown in the 2 frames below
The first frame is when fetching data from the server and the second is when the data has been received and saved to the db. It simply freezes until when it's done.

How to open another page after rewarded ad is watched in Flutter?

Flutter App.
One button that leads to the 2nd page where the content is.
The user clicks on the button and must watch a video ad(rewarded ad).
After the video ad finishes > the user can open the 2nd page / or the 2nd page will be automatically opened when he clicks 'x' on the finished video ad.
My question is > how to do this? What would the code look like and what to use?
Thank you!
Use the following code on your first page above the build method
late RewardedAd _rewardedAd;
bool _isRewardedAdReady = false;
// TODO: Implement _loadRewardedAd()
void _loadRewardedAd() {
RewardedAd.load(
adUnitId: AdHelper.rewardedAdUnitId,
request: AdRequest(),
rewardedAdLoadCallback: RewardedAdLoadCallback(
onAdLoaded: (ad) {
this._rewardedAd = ad;
ad.fullScreenContentCallback = FullScreenContentCallback(
onAdDismissedFullScreenContent: (ad) {
setState(() {
_isRewardedAdReady = false;
});
_loadRewardedAd();
},
);
setState(() {
_isRewardedAdReady = true;
});
},
onAdFailedToLoad: (err) {
print('Failed to load a rewarded ad: ${err.message}');
setState(() {
_isRewardedAdReady = false;
});
},
),
);
}
After that initialize and dispose the rewardedad like
#override
void initState() {
_loadRewardedAd();
super.initState();
}
#override
void dispose() {
_rewardedAd.dispose();
super.dispose();
}
Now call the rewarede ad with Navigating to othe page
GestureDetector(
onTap: () {
if(_isRewardedAdReady){
_rewardedAd.show(onUserEarnedReward:
(RewardedAd ad, RewardItem reward) {
print(
'$ad with reward $RewardItem(${reward.amount}, ${reward.type}');
});
}
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context)=>SecondPage()));
},
child: CustomButton(text:'GoTo Second Page')
),
for better understand go to here

Ad with the following id could not be found. Natiev Ad Flutter google_mobile_ads

the native ad is me show a an error. I use the Test ad id from google.
"This ad may have not been loaded or has been disposed. Ad with the following id could not be found:1"
Can anyone help me?
EDIT #1 My Code
There are a different example codes for native Ad?
I use google_mobile_ads: ^0.13.2
...
class _GameState extends State<Game> {
static const AdRequest targetingInfo = AdRequest(
);
static const int maxFailedLoadAttempts = 3;
static const _adUnitIDNative = "ca-app-pub-3940256099942544/2247696110";
late StreamSubscription _subscription;
bool? _deutsch;
final NativeAd myNative = NativeAd(
adUnitId: _adUnitIDNative,
factoryId: 'listTile',
request: AdRequest(),
listener: NativeAdListener(),
);
final NativeAdListener listener = NativeAdListener(
// Called when an ad is successfully received.
onAdLoaded: (Ad ad) => print('Ad loaded.'),
// Called when an ad request failed.
onAdFailedToLoad: (Ad ad, LoadAdError error) {
// Dispose the ad here to free resources.
ad.dispose();
print('NativeAd failed to load: $error');
},
// Called when an ad opens an overlay that covers the screen.
onAdOpened: (Ad ad) => print('Ad opened.'),
// Called when an ad removes an overlay that covers the screen.
onAdClosed: (Ad ad) => print('Ad closed.'),
// Called when an impression occurs on the ad.
onAdImpression: (Ad ad) => print('Ad impression.'),
// Called when a click is recorded for a NativeAd.
onNativeAdClicked: (NativeAd ad) => print('Ad clicked.'),
);
get adContainer => null;
#override
void initState() {
super.initState();
_createInterstitialAd();
myNative.load();
}
...
Container(
alignment: Alignment.center,
child: AdWidget(ad: myNative),
padding: EdgeInsets.all(10),
margin: EdgeInsets.only(bottom: 20.0),
height: 70,
),
Thanks
Your AdWidget is building before the ad has finished loading; you need to implement three things:
Boolean Flag: to indicate the ad has finished loading;
Listening event: on ad loaded, set flag to true and trigger rebuild; and
Trigger Widget: on true, build the ad widget.
// 1. Create bool
bool isAdLoaded = false;
// 2. Add listener event
final NativeAdListener listener = NativeAdListener(
// Called when an ad is successfully received.
onAdLoaded: (Ad ad) => {
setState(() {
isAdLoaded = true;
});
...
// 3. Wrap the AdWidget inside a switch
isAdLoaded ? Container(
alignment: Alignment.center,
child: AdWidget(ad: myNative),
padding: EdgeInsets.all(10),
margin: EdgeInsets.only(bottom: 20.0),
height: 70,
) : CircularProgressIndicator(),

Unable to reliably trigger animation with longPress on GestureDetector

I'm trying to create a button with a progress indicator (CircularProgressIndicator)
Desired flow:
The user taps on the button it should fire a function
The user presses the button (and holds), it should trigger the animation and fire a function
When the user releases their hold, it should reset the animation and fire a function
At this point, my code works on the second time pressing (and holding) the element. The first time around, the animation controller's addListener prints 2-3 times and then stops, whereas the second time, it holds true and continues to print as the user holds the element. Ontap functionality works regardless.
It's happening while running locally on an android and an ios device
Stripped code block:
import 'package:flutter/material.dart';
import 'package:homi_frontend/constants/woopen_colors.dart';
class ProgressButton extends StatefulWidget {
ProgressButton({
#required this.onTap,
#required this.onLongPress,
#required this.onLongPressUp,
this.duration = const Duration(seconds: 60),
});
final Function onTap;
final Function onLongPress;
final Function onLongPressUp;
final Duration duration;
#override
ProgressButtonState createState() => ProgressButtonState();
}
class ProgressButtonState extends State<ProgressButton>
with SingleTickerProviderStateMixin {
AnimationController _animationController;
bool _beingPressed = false;
#override
void initState() {
_animationController = AnimationController(
vsync: this,
duration: widget.duration,
);
_animationController.addListener(_animationListener);
_animationController.addStatusListener(_animationStatusListener);
super.initState();
}
void _animationListener() {
print('Animation Controller Listener');
setState(() {});
}
void _animationStatusListener(AnimationStatus status) {
print('_animationStatusListener');
if (status == AnimationStatus.completed) {
print(
'Completed duration of ${widget.duration}, fire _handleOnLongPressUp');
_handleOnLongPressUp();
}
if (status == AnimationStatus.forward) {
this.setState(() {
_beingPressed = true;
});
}
}
void _handleOnLongPress() {
print('_handleOnLongPress');
try {
_animationController.forward();
} catch (e) {
print('_handleOnLongPress error: ${e.toString()}');
} finally {
if (_animationController.status == AnimationStatus.forward) {
print('Controller has been started, fire widget.onLongPress');
widget.onLongPress();
}
}
}
void _handleOnLongPressUp() {
print('_handleOnLongPressUp');
try {
this.setState(() {
_beingPressed = false;
});
_animationController.reset();
} catch (e) {
print('_handleOnLongPressUp error: ${e.toString()}');
} finally {
if (_animationController.status == AnimationStatus.dismissed) {
print('Controller has been dismissed, fire widget.onLongPressUp');
widget.onLongPressUp();
}
}
}
#override
dispose() {
_animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return GestureDetector(
key: Key('progressButtonGestureDetector'),
behavior: HitTestBehavior.opaque,
onLongPress: _handleOnLongPress,
onLongPressUp: _handleOnLongPressUp,
onTap: widget.onTap,
child: Container(
width: 80,
height: 80,
child: Text(_animationController.value.toStringAsFixed(2)),
),
);
}
}
Output:
flutter: _handleOnLongPress
flutter: _animationStatusListener
flutter: Controller has been started, fire widget.onLongPress
(2) flutter: Animation Controller Listener
# here it just seems to loose its connection, but if I press (and hold) again, I get:
flutter: _handleOnLongPress
flutter: _animationStatusListener
flutter: Controller has been started, fire widget.onLongPress
(326) flutter: Animation Controller Listener
flutter: _handleOnLongPressUp
flutter: Animation Controller Listener
flutter: _animationStatusListener
flutter: Controller has been dismissed, fire widget.onLongPressUp
I've also looked briefly into RawGestureDetector but only my TapGestureRecognizer gestures seem to fire, the LongPressGestureRecognizer ones don't... even if TapGestureRecognizers are removed.
_customGestures = Map<Type, GestureRecognizerFactory>();
_customGestures[TapGestureRecognizer] =
GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>(
() => TapGestureRecognizer(debugOwner: this),
(TapGestureRecognizer instance) {
instance
..onTapDown = (TapDownDetails details) {
print('onTapDown');
}
..onTapUp = (TapUpDetails details) {
print('onTapUp');
}
..onTap = () {
print('onTap');
}
..onTapCancel = () {
print('onTapCancel');
};
},
);
_customGestures[LongPressGestureRecognizer] =
GestureRecognizerFactoryWithHandlers<LongPressGestureRecognizer>(
() => LongPressGestureRecognizer(
duration: widget.duration, debugOwner: this),
(LongPressGestureRecognizer instance) {
instance
..onLongPress = () {
print('onLongPress');
}
..onLongPressStart = (LongPressStartDetails details) {
print('onLongPressStart');
_animationController.forward();
}
..onLongPressMoveUpdate = (LongPressMoveUpdateDetails details) {
print('onLongPressMoveUpdate');
}
..onLongPressEnd = (LongPressEndDetails details) {
print('onLongPressEnd');
_animationController.reset();
}
..onLongPressUp = () {
print('onLongPressUp');
};
},
);
Please & thank you for your time!
You are using a Text widget to receive the hit within the
GestureDetector, which have a small hit box compare to the thumb. This might be the reason why you might misclick the hit box occasionally.
You can use the debugPaintPointersEnabled to see the behavior more clearly (need to do a Hot Restart if the app is running):
import 'package:flutter/rendering.dart';
void main() {
// Add the config here
debugPaintPointersEnabled = true;
runApp(App());
}
You can see that the hit box does not flash all the time, even when we think we hit the Text. To increase the accuracy, let's wrap a Container with size around the Text
GestureDetector(
// ... other lines
child: Container(
width: 100,
height: 50,
color: Colors.blue,
alignment: Alignment.center,
child:
Text('Value: ${_animationController.value.toStringAsFixed(2)}')),
);
You can see that the hit box flashes everytime now