Skip to content

Commit adb7bf5

Browse files
committed
refactor(ads): enhance interstitial ad eligibility logic and navigation handling
- Add route name tracking and eligibility check for interstitial ads - Implement logic to count only eligible page transitions - Use unawaited for ad showing to avoid navigation blocking - Improve logging and error handling - Adjust ad frequency configuration naming
1 parent cefd3b8 commit adb7bf5

File tree

1 file changed

+84
-18
lines changed

1 file changed

+84
-18
lines changed

lib/ads/ad_navigator_observer.dart

Lines changed: 84 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ class AdNavigatorObserver extends NavigatorObserver {
3636
required this.adService,
3737
required AdThemeStyle adThemeStyle,
3838
Logger? logger,
39-
}) : _logger = logger ?? Logger('AdNavigatorObserver'),
40-
_adThemeStyle = adThemeStyle;
39+
}) : _logger = logger ?? Logger('AdNavigatorObserver'),
40+
_adThemeStyle = adThemeStyle;
4141

4242
/// A function that provides the current [AppState].
4343
final AppStateProvider appStateProvider;
@@ -51,29 +51,71 @@ class AdNavigatorObserver extends NavigatorObserver {
5151
/// Tracks the number of page transitions since the last interstitial ad.
5252
int _pageTransitionCount = 0;
5353

54+
/// Stores the name of the previous route.
55+
String? _previousRouteName;
56+
5457
@override
5558
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
5659
super.didPush(route, previousRoute);
57-
_logger.info('Route pushed: ${route.settings.name}');
58-
if (route is PageRoute && route.settings.name != null) {
59-
_handlePageTransition();
60+
final currentRouteName = route.settings.name;
61+
_logger.info('Route pushed: $currentRouteName (Previous: $_previousRouteName)');
62+
if (route is PageRoute && currentRouteName != null) {
63+
_handlePageTransition(currentRouteName);
6064
}
65+
_previousRouteName = currentRouteName;
6166
}
6267

6368
@override
6469
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
6570
super.didPop(route, previousRoute);
66-
_logger.info('Route popped: ${route.settings.name}');
67-
if (route is PageRoute && route.settings.name != null) {
68-
_handlePageTransition();
71+
final currentRouteName = previousRoute?.settings.name; // After pop, previousRoute is the new current
72+
_logger.info('Route popped: ${route.settings.name} (New Current: $currentRouteName)');
73+
if (route is PageRoute && currentRouteName != null) {
74+
_handlePageTransition(currentRouteName);
6975
}
76+
_previousRouteName = currentRouteName;
7077
}
7178

72-
/// Handles a page transition event, checks ad frequency, and shows an ad if needed.
73-
void _handlePageTransition() {
74-
_pageTransitionCount++;
75-
_logger.info('Page transitioned. Current count: $_pageTransitionCount');
79+
/// Determines if a route transition is eligible for an interstitial ad.
80+
///
81+
/// An ad is considered eligible if the transition is from a content list
82+
/// (e.g., feed, search) to a detail page (e.g., article, entity details).
83+
bool _isEligibleForInterstitialAd(String currentRouteName) {
84+
// Define content list routes
85+
const contentListRoutes = {
86+
'feed',
87+
'search',
88+
'followedTopicsList',
89+
'followedSourcesList',
90+
'followedCountriesList',
91+
'accountSavedHeadlines',
92+
};
93+
94+
// Define detail page routes
95+
const detailPageRoutes = {
96+
'articleDetails',
97+
'searchArticleDetails',
98+
'accountArticleDetails',
99+
'globalArticleDetails',
100+
'entityDetails',
101+
};
102+
103+
final previous = _previousRouteName;
104+
final current = currentRouteName;
105+
106+
final isFromContentList = previous != null && contentListRoutes.contains(previous);
107+
final isToDetailPage = detailPageRoutes.contains(current);
108+
109+
_logger.info(
110+
'Eligibility check: Previous: $previous (Is Content List: $isFromContentList), '
111+
'Current: $current (Is Detail Page: $isToDetailPage)',
112+
);
113+
114+
return isFromContentList && isToDetailPage;
115+
}
76116

117+
/// Handles a page transition event, checks ad frequency, and shows an ad if needed.
118+
void _handlePageTransition(String currentRouteName) {
77119
final appState = appStateProvider();
78120
final remoteConfig = appState.remoteConfig;
79121
final user = appState.user;
@@ -87,10 +129,23 @@ class AdNavigatorObserver extends NavigatorObserver {
87129
return;
88130
}
89131

132+
// Only increment count if the transition is eligible for an interstitial ad.
133+
if (_isEligibleForInterstitialAd(currentRouteName)) {
134+
_pageTransitionCount++;
135+
_logger.info(
136+
'Eligible page transition. Current count: $_pageTransitionCount',
137+
);
138+
} else {
139+
_logger.info(
140+
'Ineligible page transition. Count remains: $_pageTransitionCount',
141+
);
142+
return; // Do not proceed if not an eligible transition
143+
}
144+
90145
final interstitialConfig =
91146
remoteConfig.adConfig.interstitialAdConfiguration;
92147
final frequencyConfig =
93-
interstitialConfig.feedInterstitialAdFrequencyConfig;
148+
interstitialConfig.feedInterstitialAdFrequencyConfig; // Using existing name
94149

95150
// Determine the required transitions based on user role.
96151
final int requiredTransitions;
@@ -111,14 +166,16 @@ class AdNavigatorObserver extends NavigatorObserver {
111166
}
112167

113168
_logger.info(
114-
'Required transitions for user role ${user?.appRole}: $requiredTransitions',
169+
'Required transitions for user role ${user?.appRole}: $requiredTransitions. '
170+
'Current eligible transitions: $_pageTransitionCount',
115171
);
116172

117173
// Check if it's time to show an interstitial ad.
118174
if (requiredTransitions > 0 &&
119175
_pageTransitionCount >= requiredTransitions) {
120176
_logger.info('Interstitial ad due. Requesting ad.');
121-
_showInterstitialAd();
177+
unawaited(_showInterstitialAd()); // Use unawaited to not block navigation
178+
// Reset count only after an ad is due (whether it shows or fails)
122179
_pageTransitionCount = 0;
123180
}
124181
}
@@ -142,15 +199,21 @@ class AdNavigatorObserver extends NavigatorObserver {
142199
// For other environments (development, production), proceed with real ad loading.
143200
// This is a secondary check. The primary check is in _handlePageTransition.
144201
if (remoteConfig == null || !remoteConfig.adConfig.enabled) {
145-
_logger.info('Interstitial ads disabled or remote config not available.');
202+
_logger.warning(
203+
'Interstitial ads disabled or remote config not available. '
204+
'This should have been caught earlier.',
205+
);
146206
return;
147207
}
148208

149209
final adConfig = remoteConfig.adConfig;
150210
final interstitialConfig = adConfig.interstitialAdConfiguration;
151211

152212
if (!interstitialConfig.enabled) {
153-
_logger.info('Interstitial ads are specifically disabled in config.');
213+
_logger.warning(
214+
'Interstitial ads are specifically disabled in config. '
215+
'This should have been caught earlier.',
216+
);
154217
return;
155218
}
156219

@@ -192,7 +255,10 @@ class AdNavigatorObserver extends NavigatorObserver {
192255
);
193256
}
194257
} else {
195-
_logger.info('No interstitial ad loaded.');
258+
_logger.warning(
259+
'No interstitial ad loaded by AdService, even though one was due. '
260+
'Check AdService implementation and ad unit availability.',
261+
);
196262
}
197263
}
198264
}

0 commit comments

Comments
 (0)