Skip to content

Commit f6636d1

Browse files
authored
Merge pull request #127 from flutter-news-app-full-source-code/build/update-deps
build(deps): update git dependencies to specific refs
2 parents fc159c0 + 3971c2d commit f6636d1

35 files changed

+274
-260
lines changed

lib/account/view/saved_headlines_page.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,7 @@ class SavedHeadlinesPage extends StatelessWidget {
9595
final headline = savedHeadlines[index];
9696
final imageStyle =
9797
appState.settings?.feedPreferences.headlineImageStyle ??
98-
HeadlineImageStyle
99-
.smallThumbnail; // Default if settings not loaded
98+
HeadlineImageStyle.smallThumbnail;
10099

101100
final trailingButton = IconButton(
102101
icon: Icon(Icons.delete_outline, color: colorScheme.error),

lib/ads/ad_service.dart

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class AdService {
5656
Future<void> disposeAd(dynamic adModel) async {
5757
// Determine the AdPlatformType from the adModel if it's an InlineAd or InterstitialAd.
5858
AdPlatformType? providerType;
59-
Object? adObject; // To hold the actual ad object
59+
Object? adObject;
6060

6161
if (adModel is InlineAd) {
6262
providerType = adModel.provider;
@@ -69,7 +69,7 @@ class AdService {
6969
if (providerType != null && adObject != null) {
7070
final adProvider = _adProviders[providerType];
7171
if (adProvider != null) {
72-
await adProvider.disposeAd(adObject); // Pass the actual ad object
72+
await adProvider.disposeAd(adObject);
7373
} else {
7474
_logger.warning(
7575
'AdService: No AdProvider found for type $providerType to dispose ad.',
@@ -95,10 +95,12 @@ class AdService {
9595
/// - [adThemeStyle]: UI-agnostic theme properties for ad styling.
9696
/// - [headlineImageStyle]: The user's preference for feed layout,
9797
/// which can be used to request an appropriately sized ad.
98+
/// - [userRole]: The current role of the user, used to determine ad visibility.
9899
Future<InlineAd?> getFeedAd({
99100
required AdConfig adConfig,
100101
required AdType adType,
101102
required AdThemeStyle adThemeStyle,
103+
required AppUserRole userRole,
102104
HeadlineImageStyle? headlineImageStyle,
103105
}) async {
104106
_logger.info('AdService: getFeedAd called for adType: $adType');
@@ -108,6 +110,7 @@ class AdService {
108110
adThemeStyle: adThemeStyle,
109111
feedAd: true,
110112
headlineImageStyle: headlineImageStyle,
113+
userRole: userRole,
111114
);
112115
}
113116

@@ -116,25 +119,37 @@ class AdService {
116119
/// This method delegates the ad loading to the appropriate [AdProvider]
117120
/// based on the [adConfig]'s `primaryAdPlatform`. It is specifically
118121
/// designed for interstitial ads that are displayed as full-screen overlays,
119-
/// typically triggered on route changes.
122+
/// typically on route changes.
120123
///
121124
/// Returns an [InterstitialAd] if an interstitial ad is available, otherwise `null`.
122125
///
123126
/// - [adConfig]: The remote configuration for ad display rules.
124127
/// - [adThemeStyle]: UI-agnostic theme properties for ad styling.
128+
/// - [userRole]: The current role of the user, used to determine ad visibility.
125129
Future<InterstitialAd?> getInterstitialAd({
126130
required AdConfig adConfig,
127131
required AdThemeStyle adThemeStyle,
132+
required AppUserRole userRole,
128133
}) async {
129134
_logger.info('AdService: getInterstitialAd called.');
130135
if (!adConfig.enabled) {
131136
_logger.info('AdService: Ads are globally disabled in RemoteConfig.');
132137
return null;
133138
}
134139

135-
// Check if interstitial ads are enabled in the remote config.
136-
if (!adConfig.interstitialAdConfiguration.enabled) {
137-
_logger.info('AdService: Interstitial ads are disabled in RemoteConfig.');
140+
// Check if interstitial ads are enabled for the current user role.
141+
final interstitialConfig = adConfig.interstitialAdConfiguration;
142+
// Check if the interstitial ads are globally enabled AND if the current
143+
// user role has a defined configuration in the visibleTo map.
144+
final isInterstitialEnabledForRole =
145+
interstitialConfig.enabled &&
146+
interstitialConfig.visibleTo.containsKey(userRole);
147+
148+
if (!isInterstitialEnabledForRole) {
149+
_logger.info(
150+
'AdService: Interstitial ads are disabled for user role $userRole '
151+
'or globally in RemoteConfig.',
152+
);
138153
return null;
139154
}
140155

@@ -216,17 +231,23 @@ class AdService {
216231
///
217232
/// - [adConfig]: The remote configuration for ad display rules.
218233
/// - [adThemeStyle]: UI-agnostic theme properties for ad styling.
234+
/// - [userRole]: The current role of the user, used to determine ad visibility.
235+
/// - [slotType]: The specific in-article ad slot type.
219236
Future<InlineAd?> getInArticleAd({
220237
required AdConfig adConfig,
221238
required AdThemeStyle adThemeStyle,
239+
required AppUserRole userRole,
240+
required InArticleAdSlotType slotType,
222241
}) async {
223242
_logger.info('AdService: getInArticleAd called.');
224243
return _loadInlineAd(
225244
adConfig: adConfig,
226-
adType: AdType.banner, // In-article ads are now always banners
245+
adType: AdType.banner,
227246
adThemeStyle: adThemeStyle,
228247
feedAd: false,
229248
bannerAdShape: adConfig.articleAdConfiguration.bannerAdShape,
249+
userRole: userRole,
250+
slotType: slotType,
230251
);
231252
}
232253

@@ -243,30 +264,57 @@ class AdService {
243264
/// - [headlineImageStyle]: The user's preference for feed layout,
244265
/// which can be used to request an appropriately sized ad.
245266
/// - [bannerAdShape]: The preferred shape for banner ads, used for in-article banners.
267+
/// - [userRole]: The current role of the user, used to determine ad visibility.
268+
/// - [slotType]: The specific in-article ad slot type, used for in-article ads.
246269
///
247270
/// Returns an [InlineAd] if an ad is successfully loaded, otherwise `null`.
248271
Future<InlineAd?> _loadInlineAd({
249272
required AdConfig adConfig,
250273
required AdType adType,
251274
required AdThemeStyle adThemeStyle,
252275
required bool feedAd,
276+
required AppUserRole userRole,
253277
HeadlineImageStyle? headlineImageStyle,
254278
BannerAdShape? bannerAdShape,
279+
InArticleAdSlotType? slotType,
255280
}) async {
256281
_logger.info(
257282
'AdService: _loadInlineAd called for adType: $adType, feedAd: $feedAd',
258283
);
259-
// Check if ads are globally enabled and specifically for the context (feed or article).
284+
// Check if ads are globally enabled.
260285
if (!adConfig.enabled) {
261286
_logger.info('AdService: Ads are globally disabled in RemoteConfig.');
262287
return null;
263288
}
264-
if (feedAd && !adConfig.feedAdConfiguration.enabled) {
265-
_logger.info('AdService: Feed ads are disabled in RemoteConfig.');
266-
return null;
289+
290+
// Check if ads are enabled for the specific context and user role.
291+
var isContextEnabled = false;
292+
if (feedAd) {
293+
final feedAdConfig = adConfig.feedAdConfiguration;
294+
// Check if feed ads are globally enabled AND if the current user role
295+
// has a defined configuration in the visibleTo map.
296+
isContextEnabled =
297+
feedAdConfig.enabled && feedAdConfig.visibleTo.containsKey(userRole);
298+
} else {
299+
// For in-article ads, check global article ad enablement and then
300+
// specific slot enablement for the user role.
301+
final articleAdConfig = adConfig.articleAdConfiguration;
302+
final isArticleAdEnabledForRole = articleAdConfig.visibleTo.containsKey(
303+
userRole,
304+
);
305+
final isSlotEnabledForRole =
306+
articleAdConfig.visibleTo[userRole]?[slotType] ?? false;
307+
isContextEnabled =
308+
articleAdConfig.enabled &&
309+
isArticleAdEnabledForRole &&
310+
isSlotEnabledForRole;
267311
}
268-
if (!feedAd && !adConfig.articleAdConfiguration.enabled) {
269-
_logger.info('AdService: In-article ads are disabled in RemoteConfig.');
312+
313+
if (!isContextEnabled) {
314+
_logger.info(
315+
'AdService: Ads are disabled for current context (feedAd: $feedAd, '
316+
'slotType: $slotType) and user role $userRole in RemoteConfig.',
317+
);
270318
return null;
271319
}
272320

lib/ads/demo_ad_provider.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class DemoAdProvider implements AdProvider {
4444
return NativeAd(
4545
id: _uuid.v4(),
4646
provider: AdPlatformType.demo,
47-
adObject: Object(), // Placeholder object
47+
adObject: Object(),
4848
templateType: headlineImageStyle == HeadlineImageStyle.largeThumbnail
4949
? NativeAdTemplateType.medium
5050
: NativeAdTemplateType.small,
@@ -65,7 +65,7 @@ class DemoAdProvider implements AdProvider {
6565
return BannerAd(
6666
id: _uuid.v4(),
6767
provider: AdPlatformType.demo,
68-
adObject: Object(), // Placeholder object
68+
adObject: Object(),
6969
);
7070
}
7171

@@ -82,7 +82,7 @@ class DemoAdProvider implements AdProvider {
8282
return InterstitialAd(
8383
id: _uuid.v4(),
8484
provider: AdPlatformType.demo,
85-
adObject: Object(), // Placeholder object
85+
adObject: Object(),
8686
);
8787
}
8888

lib/ads/inline_ad_cache_service.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ class InlineAdCacheService {
109109
final ad = _cache[id];
110110
if (ad != null) {
111111
_logger.info('Removing and disposing inline ad with ID "$id".');
112-
_adService.disposeAd(ad); // Delegate disposal to AdService
112+
_adService.disposeAd(ad);
113113
_cache.remove(id);
114114
} else {
115115
_logger.info('Inline ad with ID "$id" not found in cache for disposal.');
@@ -126,9 +126,9 @@ class InlineAdCacheService {
126126
'Clearing all cached inline ads and disposing their resources.',
127127
);
128128
for (final ad in _cache.values.whereType<InlineAd>()) {
129-
_adService.disposeAd(ad); // Delegate disposal to AdService
129+
_adService.disposeAd(ad);
130130
}
131-
_cache.clear(); // Ensure cache is empty after disposal attempts.
131+
_cache.clear();
132132
_logger.info('All cached inline ads cleared.');
133133
}
134134

lib/ads/interstitial_ad_manager.dart

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ class InterstitialAdManager {
124124
final ad = await _adService.getInterstitialAd(
125125
adConfig: adConfig,
126126
adThemeStyle: adThemeStyle,
127+
userRole: _userRole ?? AppUserRole.guestUser,
127128
);
128129

129130
if (ad != null) {
@@ -165,14 +166,17 @@ class InterstitialAdManager {
165166
}
166167

167168
final frequencyConfig =
168-
adConfig.interstitialAdConfiguration.feedInterstitialAdFrequencyConfig;
169-
final requiredTransitions = _getRequiredTransitions(frequencyConfig);
169+
adConfig.interstitialAdConfiguration.visibleTo[_userRole];
170+
171+
// If no frequency config is found for the user role, or if it's explicitly
172+
// disabled (transitionsBeforeShowingInterstitialAds == 0), then no ad should be shown.
173+
final requiredTransitions =
174+
frequencyConfig?.transitionsBeforeShowingInterstitialAds ?? 0;
170175

171176
if (requiredTransitions > 0 && _transitionCount >= requiredTransitions) {
172177
_logger.info('Transition count meets threshold. Attempting to show ad.');
173178
await _showAd();
174-
_transitionCount =
175-
0; // Reset counter after showing (or attempting to show)
179+
_transitionCount = 0;
176180
} else {
177181
_logger.info(
178182
'Transition count ($_transitionCount) has not met threshold ($requiredTransitions).',
@@ -197,7 +201,7 @@ class InterstitialAdManager {
197201
}
198202

199203
final adToShow = _preloadedAd!;
200-
_preloadedAd = null; // Clear the pre-loaded ad before showing
204+
_preloadedAd = null;
201205

202206
try {
203207
switch (adToShow.provider) {
@@ -230,7 +234,7 @@ class InterstitialAdManager {
230234
} finally {
231235
// After the ad is shown or fails to show, dispose of it and
232236
// start pre-loading the next one for the next opportunity.
233-
_disposePreloadedAd(); // Ensure the ad object is disposed
237+
_disposePreloadedAd();
234238
unawaited(_maybePreloadAd(_appBloc.state));
235239
}
236240
}
@@ -268,7 +272,7 @@ class InterstitialAdManager {
268272
// Await the result of showDialog, which completes when the dialog is popped.
269273
await showDialog<void>(
270274
context: context,
271-
barrierDismissible: false, // Prevent dismissing by tapping outside
275+
barrierDismissible: false,
272276
builder: (_) => LocalInterstitialAdDialog(
273277
localInterstitialAd: ad.adObject as LocalInterstitialAd,
274278
),
@@ -279,22 +283,8 @@ class InterstitialAdManager {
279283
// Await the result of showDialog, which completes when the dialog is popped.
280284
await showDialog<void>(
281285
context: context,
282-
barrierDismissible: false, // Prevent dismissing by tapping outside
286+
barrierDismissible: false,
283287
builder: (_) => const DemoInterstitialAdDialog(),
284288
);
285289
}
286-
287-
/// Determines the required number of transitions based on the user's role.
288-
int _getRequiredTransitions(InterstitialAdFrequencyConfig config) {
289-
switch (_userRole) {
290-
case AppUserRole.guestUser:
291-
return config.guestTransitionsBeforeShowingInterstitialAds;
292-
case AppUserRole.standardUser:
293-
return config.standardUserTransitionsBeforeShowingInterstitialAds;
294-
case AppUserRole.premiumUser:
295-
return config.premiumUserTransitionsBeforeShowingInterstitialAds;
296-
case null:
297-
return config.guestTransitionsBeforeShowingInterstitialAds;
298-
}
299-
}
300290
}

lib/ads/local_ad_provider.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class LocalAdProvider implements AdProvider {
4343
required AdPlatformIdentifiers adPlatformIdentifiers,
4444
required String? adId,
4545
required AdThemeStyle adThemeStyle,
46-
HeadlineImageStyle? headlineImageStyle, // Added for interface consistency
46+
HeadlineImageStyle? headlineImageStyle,
4747
}) async {
4848
_logger.info('LocalAdProvider: loadNativeAd called for adId: $adId');
4949
if (adId == null || adId.isEmpty) {
@@ -97,7 +97,7 @@ class LocalAdProvider implements AdProvider {
9797
required AdPlatformIdentifiers adPlatformIdentifiers,
9898
required String? adId,
9999
required AdThemeStyle adThemeStyle,
100-
HeadlineImageStyle? headlineImageStyle, // Added for interface consistency
100+
HeadlineImageStyle? headlineImageStyle,
101101
}) async {
102102
_logger.info('LocalAdProvider: loadBannerAd called for adId: $adId');
103103
if (adId == null || adId.isEmpty) {

lib/ads/widgets/admob_inline_ad_widget.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class _AdmobInlineAdWidgetState extends State<AdmobInlineAdWidget> {
5959
// and set the new one. This is a more robust check than just comparing IDs,
6060
// as a new InlineAd instance might be created for the same logical ad slot.
6161
if (widget.inlineAd != oldWidget.inlineAd) {
62-
_disposeCurrentAd(); // Dispose the old ad object
62+
_disposeCurrentAd();
6363
_setAd();
6464
}
6565
}

lib/ads/widgets/demo_banner_ad_widget.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ class DemoBannerAdWidget extends StatelessWidget {
3838
};
3939
} else {
4040
adHeight = headlineImageStyle == HeadlineImageStyle.largeThumbnail
41-
? 250 // Height for mediumRectangle banner
42-
: 50; // Height for standard banner
41+
? 250
42+
: 50;
4343
}
4444

4545
return Card(

lib/ads/widgets/demo_native_ad_widget.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ class DemoNativeAdWidget extends StatelessWidget {
2323

2424
// Determine the height based on the headlineImageStyle, mimicking real ad widgets.
2525
final adHeight = headlineImageStyle == HeadlineImageStyle.largeThumbnail
26-
? 250 // Height for medium native ad template
27-
: 120; // Height for small native ad template
26+
? 250
27+
: 120;
2828

2929
return Card(
3030
margin: const EdgeInsets.symmetric(

0 commit comments

Comments
 (0)