Skip to content

Commit 70434ca

Browse files
authored
Merge pull request #38 from flutter-news-app-full-source-code/Ad-Configuration-Overhaul
Ad configuration overhaul
2 parents 4d21840 + 1150fa4 commit 70434ca

36 files changed

+1723
-202
lines changed

lib/src/enums/ad_platform_type.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/// {@template ad_platform_type}
2+
/// Defines the single ad platform to be used across the entire application.
3+
/// {@endtemplate}
4+
enum AdPlatformType {
5+
/// Google AdMob platform.
6+
admob,
7+
8+
/// Local custom ad platform.
9+
local,
10+
}

lib/src/enums/enums.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export 'ad_platform_type.dart';
12
export 'app_accent_theme.dart';
23
export 'app_base_theme.dart';
34
export 'app_font_weight.dart';
@@ -10,5 +11,6 @@ export 'feed_decorator_category.dart';
1011
export 'feed_decorator_type.dart';
1112
export 'headline_density.dart';
1213
export 'headline_image_style.dart';
14+
export 'in_article_ad_slot_type.dart';
1315
export 'sort_order.dart';
1416
export 'source_type.dart';
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/// {@template in_article_ad_slot_type}
2+
/// Defines specific, standard locations for ads within an article's content.
3+
/// {@endtemplate}
4+
enum InArticleAdSlotType {
5+
/// Ad placed directly below the main article image.
6+
belowMainArticleImage,
7+
8+
/// Ad placed just before a "Continue Reading" button.
9+
aboveArticleContinueReadingButton,
10+
11+
/// Ad placed just after a "Continue Reading" button.
12+
belowArticleContinueReadingButton,
13+
}

lib/src/fixtures/remote_configs.dart

Lines changed: 98 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,104 @@ final List<RemoteConfig> remoteConfigsFixturesData = [
2424
premiumSavedHeadlinesLimit: 100,
2525
),
2626
adConfig: const AdConfig(
27-
guestAdFrequency: 5,
28-
guestAdPlacementInterval: 3,
29-
authenticatedAdFrequency: 10,
30-
authenticatedAdPlacementInterval: 5,
31-
premiumAdFrequency: 0,
32-
premiumAdPlacementInterval: 0,
33-
guestArticlesToReadBeforeShowingInterstitialAds: 5,
34-
standardUserArticlesToReadBeforeShowingInterstitialAds: 10,
35-
premiumUserArticlesToReadBeforeShowingInterstitialAds: 50000,
27+
primaryAdPlatform: AdPlatformType.admob,
28+
platformAdIdentifiers: {
29+
AdPlatformType.admob: AdPlatformIdentifiers(
30+
feedNativeAdId: 'ca-app-pub-3940256099942544/2247696110',
31+
feedBannerAdId: 'ca-app-pub-3940256099942544/6300978111',
32+
articleInterstitialAdId: 'ca-app-pub-3940256099942544/1033173712',
33+
inArticleNativeAdId: 'ca-app-pub-3940256099942544/3986624511',
34+
inArticleBannerAdId: 'ca-app-pub-3940256099942544/6300978111',
35+
),
36+
AdPlatformType.local: AdPlatformIdentifiers(
37+
feedNativeAdId: 'local_feed_native_ad_id',
38+
feedBannerAdId: 'local_feed_banner_ad_id',
39+
articleInterstitialAdId: 'local_article_interstitial_ad_id',
40+
inArticleNativeAdId: 'local_in_article_native_ad_id',
41+
inArticleBannerAdId: 'local_in_article_banner_ad_id',
42+
),
43+
},
44+
localAdsCatalog: {
45+
'local_feed_native_ad_id': LocalAd(
46+
id: 'local_feed_native_ad_id',
47+
title: 'Local Native Ad Title',
48+
subtitle: 'This is a local native ad description.',
49+
imageUrl: 'https://example.com/local_native_ad.png',
50+
targetUrl: 'https://example.com/local_native_ad_target',
51+
adType: AdType.native,
52+
),
53+
'local_feed_banner_ad_id': LocalAd(
54+
id: 'local_feed_banner_ad_id',
55+
title: 'Local Banner Ad Title',
56+
subtitle: 'This is a local banner ad description.',
57+
imageUrl: 'https://example.com/local_banner_ad.png',
58+
targetUrl: 'https://example.com/local_banner_ad_target',
59+
adType: AdType.banner,
60+
),
61+
'local_article_interstitial_ad_id': LocalAd(
62+
id: 'local_article_interstitial_ad_id',
63+
title: 'Local Interstitial Ad Title',
64+
subtitle: 'This is a local interstitial ad description.',
65+
imageUrl: 'https://example.com/local_interstitial_ad.png',
66+
targetUrl: 'https://example.com/local_interstitial_ad_target',
67+
adType: AdType.interstitial,
68+
),
69+
'local_in_article_native_ad_id': LocalAd(
70+
id: 'local_in_article_native_ad_id',
71+
title: 'Local In-Article Native Ad Title',
72+
subtitle: 'This is a local in-article native ad description.',
73+
imageUrl: 'https://example.com/local_in_article_native_ad.png',
74+
targetUrl: 'https://example.com/local_in_article_native_ad_target',
75+
adType: AdType.native,
76+
),
77+
'local_in_article_banner_ad_id': LocalAd(
78+
id: 'local_in_article_banner_ad_id',
79+
title: 'Local In-Article Banner Ad Title',
80+
subtitle: 'This is a local in-article banner ad description.',
81+
imageUrl: 'https://example.com/local_in_article_banner_ad.png',
82+
targetUrl: 'https://example.com/local_in_article_banner_ad_target',
83+
adType: AdType.banner,
84+
),
85+
},
86+
feedAdConfiguration: FeedAdConfiguration(
87+
enabled: true,
88+
adType: AdType.native,
89+
frequencyConfig: FeedAdFrequencyConfig(
90+
guestAdFrequency: 5,
91+
guestAdPlacementInterval: 3,
92+
authenticatedAdFrequency: 10,
93+
authenticatedAdPlacementInterval: 5,
94+
premiumAdFrequency: 0,
95+
premiumAdPlacementInterval: 0,
96+
),
97+
),
98+
articleAdConfiguration: ArticleAdConfiguration(
99+
enabled: true,
100+
defaultInArticleAdType: AdType.native,
101+
interstitialAdConfiguration: ArticleInterstitialAdConfiguration(
102+
enabled: true,
103+
adType: AdType.interstitial,
104+
frequencyConfig: ArticleInterstitialAdFrequencyConfig(
105+
guestArticlesToReadBeforeShowingInterstitialAds: 5,
106+
standardUserArticlesToReadBeforeShowingInterstitialAds: 10,
107+
premiumUserArticlesToReadBeforeShowingInterstitialAds: 50000,
108+
),
109+
),
110+
inArticleAdSlotConfigurations: [
111+
InArticleAdSlotConfiguration(
112+
slotType: InArticleAdSlotType.belowMainArticleImage,
113+
enabled: true,
114+
),
115+
InArticleAdSlotConfiguration(
116+
slotType: InArticleAdSlotType.aboveArticleContinueReadingButton,
117+
enabled: true,
118+
),
119+
InArticleAdSlotConfiguration(
120+
slotType: InArticleAdSlotType.belowArticleContinueReadingButton,
121+
enabled: true,
122+
),
123+
],
124+
),
36125
),
37126
feedDecoratorConfig: const {
38127
FeedDecoratorType.rateApp: FeedDecoratorConfig(

lib/src/models/config/ad_config.dart

Lines changed: 44 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,131 +1,77 @@
1-
import 'package:core/src/models/config/remote_config.dart';
1+
import 'package:core/src/enums/ad_platform_type.dart';
2+
import 'package:core/src/models/config/ad_platform_identifiers.dart';
3+
import 'package:core/src/models/config/article_ad_configuration.dart';
4+
import 'package:core/src/models/config/feed_ad_configuration.dart';
5+
import 'package:core/src/models/config/local_ad.dart';
26
import 'package:equatable/equatable.dart';
37
import 'package:json_annotation/json_annotation.dart';
48
import 'package:meta/meta.dart';
59

610
part 'ad_config.g.dart';
711

812
/// {@template ad_config}
9-
/// Defines configuration settings related to ad injection and display,
10-
/// tiered by user role.
11-
///
12-
/// This model is part of the overall [RemoteConfig] and is used to control
13-
/// how ads are integrated into the application's feed or other content areas
14-
/// based on the user's authentication status or subscription level.
15-
///
16-
/// **Ad Injection Logic Explained:**
17-
///
18-
/// - __`AdFrequency`__: This determines *how often* an ad *can* be injected relative to the number of primary content items. For example, an `adFrequency` of 5 means an ad *could* be placed after every 5 primary items. It sets the overall density of ads in the feed.
19-
///
20-
/// - __`AdPlacementInterval`__: This sets a *minimum number of primary items* that must appear *before* the *first* ad is placed. It prevents ads from appearing right at the very beginning of the feed, ensuring the user sees some initial content first.
21-
///
22-
/// So, `AdFrequency` controls the spacing of ads *throughout* the feed (after the initial interval), while `AdPlacementInterval` controls where the *very first* ad can appear.
23-
///
24-
/// Think of it like this:
25-
///
26-
/// - `AdPlacementInterval` = 3: No ads will appear in the first 3 primary items.
27-
/// - `AdFrequency` = 5: After the first 3 items, an ad *could* appear after item #5, then potentially after item #10, #15, etc.
13+
/// This is the main container for all ad-related configurations.
2814
/// {@endtemplate}
2915
@immutable
3016
@JsonSerializable(explicitToJson: true, includeIfNull: true, checked: true)
3117
class AdConfig extends Equatable {
3218
/// {@macro ad_config}
3319
const AdConfig({
34-
required this.guestAdFrequency,
35-
required this.guestAdPlacementInterval,
36-
required this.authenticatedAdFrequency,
37-
required this.authenticatedAdPlacementInterval,
38-
required this.premiumAdFrequency,
39-
required this.premiumAdPlacementInterval,
40-
required this.guestArticlesToReadBeforeShowingInterstitialAds,
41-
required this.standardUserArticlesToReadBeforeShowingInterstitialAds,
42-
required this.premiumUserArticlesToReadBeforeShowingInterstitialAds,
20+
required this.primaryAdPlatform,
21+
required this.platformAdIdentifiers,
22+
required this.localAdsCatalog,
23+
required this.feedAdConfiguration,
24+
required this.articleAdConfiguration,
4325
});
4426

45-
/// Factory method to create an [AdConfig] instance from a JSON map.
27+
/// Creates an [AdConfig] from JSON data.
4628
factory AdConfig.fromJson(Map<String, dynamic> json) =>
4729
_$AdConfigFromJson(json);
4830

49-
/// See class documentation for details on AdFrequency.
50-
final int guestAdFrequency;
51-
52-
/// See class documentation for details on AdPlacementInterval.
53-
final int guestAdPlacementInterval;
54-
55-
/// See class documentation for details on AdFrequency.
56-
final int authenticatedAdFrequency;
57-
58-
/// See class documentation for details on AdPlacementInterval.
59-
final int authenticatedAdPlacementInterval;
31+
/// Converts this [AdConfig] instance to JSON data.
32+
Map<String, dynamic> toJson() => _$AdConfigToJson(this);
6033

61-
/// See class documentation for details on AdFrequency.
62-
final int premiumAdFrequency;
34+
/// Global choice: AdMob or Local.
35+
final AdPlatformType primaryAdPlatform;
6336

64-
/// See class documentation for details on AdPlacementInterval.
65-
final int premiumAdPlacementInterval;
37+
/// Map to store identifiers for all platforms.
38+
final Map<AdPlatformType, AdPlatformIdentifiers> platformAdIdentifiers;
6639

67-
/// The number of articles a guest user needs to read before an
68-
/// interstitial ad is shown.
69-
final int guestArticlesToReadBeforeShowingInterstitialAds;
40+
/// All defined local ads by ID.
41+
final Map<String, LocalAd> localAdsCatalog;
7042

71-
/// The number of articles a standard user needs to read before an
72-
/// interstitial ad is shown.
73-
final int standardUserArticlesToReadBeforeShowingInterstitialAds;
43+
/// Configuration for main feed, search feed, similar headlines feed.
44+
final FeedAdConfiguration feedAdConfiguration;
7445

75-
/// The number of articles a premium user needs to read before an
76-
/// interstitial ad is shown.
77-
final int premiumUserArticlesToReadBeforeShowingInterstitialAds;
46+
/// Configuration for article page ads.
47+
final ArticleAdConfiguration articleAdConfiguration;
7848

79-
/// Converts this [AdConfig] instance to a JSON map.
80-
Map<String, dynamic> toJson() => _$AdConfigToJson(this);
49+
@override
50+
List<Object> get props => [
51+
primaryAdPlatform,
52+
platformAdIdentifiers,
53+
localAdsCatalog,
54+
feedAdConfiguration,
55+
articleAdConfiguration,
56+
];
8157

8258
/// Creates a copy of this [AdConfig] but with the given fields replaced
8359
/// with the new values.
8460
AdConfig copyWith({
85-
int? guestAdFrequency,
86-
int? guestAdPlacementInterval,
87-
int? authenticatedAdFrequency,
88-
int? authenticatedAdPlacementInterval,
89-
int? premiumAdFrequency,
90-
int? premiumAdPlacementInterval,
91-
int? guestArticlesToReadBeforeShowingInterstitialAds,
92-
int? standardUserArticlesToReadBeforeShowingInterstitialAds,
93-
int? premiumUserArticlesToReadBeforeShowingInterstitialAds,
61+
AdPlatformType? primaryAdPlatform,
62+
Map<AdPlatformType, AdPlatformIdentifiers>? platformAdIdentifiers,
63+
Map<String, LocalAd>? localAdsCatalog,
64+
FeedAdConfiguration? feedAdConfiguration,
65+
ArticleAdConfiguration? articleAdConfiguration,
9466
}) {
9567
return AdConfig(
96-
guestAdFrequency: guestAdFrequency ?? this.guestAdFrequency,
97-
guestAdPlacementInterval:
98-
guestAdPlacementInterval ?? this.guestAdPlacementInterval,
99-
authenticatedAdFrequency:
100-
authenticatedAdFrequency ?? this.authenticatedAdFrequency,
101-
authenticatedAdPlacementInterval:
102-
authenticatedAdPlacementInterval ??
103-
this.authenticatedAdPlacementInterval,
104-
premiumAdFrequency: premiumAdFrequency ?? this.premiumAdFrequency,
105-
premiumAdPlacementInterval:
106-
premiumAdPlacementInterval ?? this.premiumAdPlacementInterval,
107-
guestArticlesToReadBeforeShowingInterstitialAds:
108-
guestArticlesToReadBeforeShowingInterstitialAds ??
109-
this.guestArticlesToReadBeforeShowingInterstitialAds,
110-
standardUserArticlesToReadBeforeShowingInterstitialAds:
111-
standardUserArticlesToReadBeforeShowingInterstitialAds ??
112-
this.standardUserArticlesToReadBeforeShowingInterstitialAds,
113-
premiumUserArticlesToReadBeforeShowingInterstitialAds:
114-
premiumUserArticlesToReadBeforeShowingInterstitialAds ??
115-
this.premiumUserArticlesToReadBeforeShowingInterstitialAds,
68+
primaryAdPlatform: primaryAdPlatform ?? this.primaryAdPlatform,
69+
platformAdIdentifiers:
70+
platformAdIdentifiers ?? this.platformAdIdentifiers,
71+
localAdsCatalog: localAdsCatalog ?? this.localAdsCatalog,
72+
feedAdConfiguration: feedAdConfiguration ?? this.feedAdConfiguration,
73+
articleAdConfiguration:
74+
articleAdConfiguration ?? this.articleAdConfiguration,
11675
);
11776
}
118-
119-
@override
120-
List<Object> get props => [
121-
guestAdFrequency,
122-
guestAdPlacementInterval,
123-
authenticatedAdFrequency,
124-
authenticatedAdPlacementInterval,
125-
premiumAdFrequency,
126-
premiumAdPlacementInterval,
127-
guestArticlesToReadBeforeShowingInterstitialAds,
128-
standardUserArticlesToReadBeforeShowingInterstitialAds,
129-
premiumUserArticlesToReadBeforeShowingInterstitialAds,
130-
];
13177
}

0 commit comments

Comments
 (0)