-
Notifications
You must be signed in to change notification settings - Fork 0
Refactor local ad into specific ad subtypes #40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 20 commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
2e3c8e8
feat(models): add local video ad model
fulleni 0e44cd6
feat(models): add local native ad model
fulleni 83d53b1
feat(models): add local interstitial ad feed item
fulleni fdea697
feat(models): add local banner ad feed item
fulleni 04758ad
feat(models): add local ad exports to feed decorators
fulleni 0268c49
feat(core): add local ads fixtures for development
fulleni ffc888b
refactor(local_ad): transform LocalAd into an abstract base class
fulleni 9ef7572
refactor(LocalBannerAd): update class hierarchy and JSON serialization
fulleni 717dbf5
feat(LocalInterstitialAd): inherit from LocalAd and update JSON seria…
fulleni 5d6e0e8
refactor(LocalNativeAd): extend LocalAd instead of FeedItem
fulleni a09739d
refactor(LocalVideoAd): extend LocalAd instead of FeedItem
fulleni 5131eea
refactor(local_ad): remove JSON serialization and simplify ad type ha…
fulleni 13549dd
refactor(LocalBannerAd): adjust JSON serialization and property list
fulleni dc66c4f
refactor(LocalInterstitialAd): update adType to string and simplify t…
fulleni e3ce76c
refactor(LocalNativeAd): update adType to string and remove overrides
fulleni 38c298c
refactor(local_video_ad): simplify adType handling and remove props o…
fulleni 3a63181
style: format
fulleni 8db4465
fix(core): replace placeholder ad IDs with predefined ones
fulleni 508f398
test(feed_item): update tests to use fixtures for local ads
fulleni 0ccf692
test(local_ad): migrate unit tests to support abstract LocalAd class …
fulleni 50a86db
refactor(fixture_ids): rename local ad id constants
fulleni bfde6e5
refactor(fixtures): replace local ad IDs with constants
fulleni 381564f
refactor(models): reorganize local ads classes and update exports
fulleni 4b96821
style(local_ad): fix typo in exception message
fulleni 5c2ba56
style: format
fulleni File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import 'package:core/core.dart'; | ||
|
||
/// A list of predefined local ads for fixture data. | ||
final localAdsFixturesData = <LocalAd>[ | ||
const LocalNativeAd( | ||
id: localAd1, | ||
title: 'Discover Our Premium Content', | ||
subtitle: 'Unlock exclusive articles and an ad-free experience.', | ||
imageUrl: 'https://example.com/ads/premium_native.png', | ||
targetUrl: 'https://example.com/premium', | ||
), | ||
const LocalBannerAd( | ||
id: localAd2, | ||
imageUrl: 'https://example.com/ads/banner_ad_1.png', | ||
targetUrl: 'https://example.com/offer1', | ||
), | ||
const LocalInterstitialAd( | ||
id: localAd3, | ||
imageUrl: 'https://example.com/ads/interstitial_ad_1.png', | ||
targetUrl: 'https://example.com/special_offer', | ||
), | ||
const LocalVideoAd( | ||
id: localAd4, | ||
videoUrl: 'https://example.com/ads/promo_video.mp4', | ||
targetUrl: 'https://example.com/watch_more', | ||
), | ||
const LocalNativeAd( | ||
id: localAd5, | ||
title: 'Stay Informed with Daily Briefings', | ||
subtitle: 'Get the top news delivered straight to your inbox.', | ||
imageUrl: 'https://example.com/ads/briefing_native.png', | ||
targetUrl: 'https://example.com/subscribe', | ||
), | ||
const LocalBannerAd( | ||
id: localAd6, | ||
imageUrl: 'https://example.com/ads/banner_ad_2.png', | ||
targetUrl: 'https://example.com/offer2', | ||
), | ||
]; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,7 @@ | ||
export 'call_to_action_item.dart'; | ||
export 'content_collection_item.dart'; | ||
export 'local_ad.dart'; | ||
export 'local_banner_ad.dart'; | ||
export 'local_interstitial_ad.dart'; | ||
export 'local_native_ad.dart'; | ||
export 'local_video_ad.dart'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,83 +1,47 @@ | ||
import 'package:core/core.dart'; | ||
import 'package:json_annotation/json_annotation.dart'; | ||
import 'package:meta/meta.dart'; | ||
|
||
part 'local_ad.g.dart'; | ||
|
||
/// {@template local_ad} | ||
/// Defines a single custom ad that can be served locally. | ||
/// Includes title and subtitle to mimic native ads. | ||
/// An abstract base class for all local ad types. | ||
/// | ||
/// This class acts as a router for deserializing specific local ad types | ||
/// (e.g., native, banner, interstitial, video) based on their `adType` field. | ||
/// Concrete implementations must provide their own `toJson` method. | ||
/// {@endtemplate} | ||
@immutable | ||
@JsonSerializable(explicitToJson: true, includeIfNull: true, checked: true) | ||
class LocalAd extends FeedItem { | ||
abstract class LocalAd extends FeedItem { | ||
/// {@macro local_ad} | ||
const LocalAd({ | ||
required this.id, | ||
required this.title, | ||
required this.subtitle, | ||
required this.imageUrl, | ||
required this.targetUrl, | ||
required this.adType, | ||
}) : super(type: 'localAd'); | ||
|
||
/// Creates a [LocalAd] from JSON data. | ||
factory LocalAd.fromJson(Map<String, dynamic> json) => | ||
_$LocalAdFromJson(json); | ||
|
||
/// Converts this [LocalAd] instance to JSON data. | ||
Map<String, dynamic> toJson() { | ||
final json = _$LocalAdToJson(this); | ||
json['type'] = type; | ||
return json; | ||
const LocalAd({required this.adType}) : super(type: 'localAd'); | ||
|
||
/// Factory method to create a [LocalAd] instance from a JSON map. | ||
/// | ||
/// This factory uses the `adType` field in the JSON map to dispatch to the | ||
/// correct concrete `fromJson` constructor for each local ad type. | ||
/// | ||
/// Throws [FormatException] if the `adType` field is missing or unknown. | ||
factory LocalAd.fromJson(Map<String, dynamic> json) { | ||
final adType = json['adType'] as String?; | ||
if (adType == null) { | ||
throw const FormatException('Missing "adType" field in LocalAd JSON.'); | ||
} | ||
|
||
switch (adType) { | ||
case 'native': | ||
return LocalNativeAd.fromJson(json); | ||
case 'banner': | ||
return LocalBannerAd.fromJson(json); | ||
case 'interstitial': | ||
return LocalInterstitialAd.fromJson(json); | ||
case 'video': | ||
return LocalVideoAd.fromJson(json); | ||
default: | ||
throw FormatException('Unknown LocalAds type: $adType'); | ||
fulleni marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
|
||
/// Unique identifier for the local ad. | ||
final String id; | ||
|
||
/// The title of the local ad. | ||
final String title; | ||
|
||
/// The subtitle or description of the local ad. | ||
final String subtitle; | ||
|
||
/// The URL of the image for the local ad. | ||
final String imageUrl; | ||
|
||
/// The URL to navigate to when the local ad is clicked. | ||
final String targetUrl; | ||
|
||
/// The type of the ad (e.g., banner, native, interstitial). | ||
final AdType adType; | ||
/// The type of the ad (e.g., banner, native, interstitial, video). | ||
final String adType; | ||
|
||
@override | ||
List<Object?> get props => [ | ||
id, | ||
title, | ||
subtitle, | ||
imageUrl, | ||
targetUrl, | ||
adType, | ||
type, | ||
]; | ||
|
||
/// Creates a copy of this [LocalAd] but with the given fields replaced with | ||
/// the new values. | ||
LocalAd copyWith({ | ||
String? id, | ||
String? title, | ||
String? subtitle, | ||
String? imageUrl, | ||
String? targetUrl, | ||
AdType? adType, | ||
}) { | ||
return LocalAd( | ||
id: id ?? this.id, | ||
title: title ?? this.title, | ||
subtitle: subtitle ?? this.subtitle, | ||
imageUrl: imageUrl ?? this.imageUrl, | ||
targetUrl: targetUrl ?? this.targetUrl, | ||
adType: adType ?? this.adType, | ||
); | ||
} | ||
List<Object?> get props => [adType, type]; | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import 'package:core/core.dart'; | ||
import 'package:json_annotation/json_annotation.dart'; | ||
import 'package:meta/meta.dart'; | ||
|
||
part 'local_banner_ad.g.dart'; | ||
|
||
/// {@template local_banner_ad} | ||
/// Defines a custom banner ad that can be served locally. | ||
/// | ||
/// Banner ads are typically rectangular images with a target URL. | ||
/// {@endtemplate} | ||
@immutable | ||
@JsonSerializable(explicitToJson: true, includeIfNull: true, checked: true) | ||
class LocalBannerAd extends LocalAd { | ||
/// {@macro local_banner_ad} | ||
const LocalBannerAd({ | ||
required this.id, | ||
required this.imageUrl, | ||
required this.targetUrl, | ||
}) : super(adType: 'banner'); | ||
|
||
/// Creates a [LocalBannerAd] from JSON data. | ||
factory LocalBannerAd.fromJson(Map<String, dynamic> json) => | ||
_$LocalBannerAdFromJson(json); | ||
|
||
/// Unique identifier for the local banner ad. | ||
final String id; | ||
|
||
/// The URL of the image for the local banner ad. | ||
final String imageUrl; | ||
|
||
/// The URL to navigate to when the local banner ad is clicked. | ||
final String targetUrl; | ||
|
||
Map<String, dynamic> toJson() { | ||
final json = _$LocalBannerAdToJson(this); | ||
json['adType'] = adType; | ||
json['type'] = type; | ||
return json; | ||
} | ||
|
||
@override | ||
List<Object?> get props => [id, imageUrl, targetUrl, adType, type]; | ||
|
||
/// Creates a copy of this [LocalBannerAd] but with the given fields replaced with | ||
/// the new values. | ||
LocalBannerAd copyWith({String? id, String? imageUrl, String? targetUrl}) { | ||
return LocalBannerAd( | ||
id: id ?? this.id, | ||
imageUrl: imageUrl ?? this.imageUrl, | ||
targetUrl: targetUrl ?? this.targetUrl, | ||
); | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import 'package:core/core.dart'; | ||
import 'package:json_annotation/json_annotation.dart'; | ||
import 'package:meta/meta.dart'; | ||
|
||
part 'local_interstitial_ad.g.dart'; | ||
|
||
/// {@template local_interstitial_ad} | ||
/// Defines a custom interstitial ad that can be served locally. | ||
/// | ||
/// Interstitial ads are full-screen advertisements, typically with an image | ||
/// and a target URL, that appear between content transitions. | ||
/// {@endtemplate} | ||
@immutable | ||
@JsonSerializable(explicitToJson: true, includeIfNull: true, checked: true) | ||
class LocalInterstitialAd extends LocalAd { | ||
/// {@macro local_interstitial_ad} | ||
const LocalInterstitialAd({ | ||
required this.id, | ||
required this.imageUrl, | ||
required this.targetUrl, | ||
}) : super(adType: 'interstitial'); | ||
|
||
/// Creates a [LocalInterstitialAd] from JSON data. | ||
factory LocalInterstitialAd.fromJson(Map<String, dynamic> json) => | ||
_$LocalInterstitialAdFromJson(json); | ||
|
||
/// Unique identifier for the local interstitial ad. | ||
final String id; | ||
|
||
/// The URL of the image for the local interstitial ad. | ||
final String imageUrl; | ||
|
||
/// The URL to navigate to when the local interstitial ad is clicked. | ||
final String targetUrl; | ||
|
||
Map<String, dynamic> toJson() { | ||
final json = _$LocalInterstitialAdToJson(this); | ||
json['adType'] = adType; | ||
json['type'] = type; | ||
return json; | ||
} | ||
|
||
@override | ||
List<Object?> get props => [id, imageUrl, targetUrl, adType, type]; | ||
|
||
/// Creates a copy of this [LocalInterstitialAd] but with the given fields | ||
/// replaced with the new values. | ||
LocalInterstitialAd copyWith({ | ||
String? id, | ||
String? imageUrl, | ||
String? targetUrl, | ||
}) { | ||
return LocalInterstitialAd( | ||
id: id ?? this.id, | ||
imageUrl: imageUrl ?? this.imageUrl, | ||
targetUrl: targetUrl ?? this.targetUrl, | ||
); | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
lib/src/models/feed_decorators/local_interstitial_ad.g.dart
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.