Files
BlockSeasons/lib/services/ad_frequency_policy.dart
T

48 lines
1.6 KiB
Dart

/// Pure-Dart interstitial gate. No plugin imports so the monetization rules
/// are unit-tested headlessly. The service layer feeds it lifecycle events
/// and asks [canShowInterstitial] before every stage-end interstitial.
class AdFrequencyPolicy {
AdFrequencyPolicy({
this.minStagesBetween = 3,
this.minInterval = const Duration(seconds: 90),
this.firstStagesProtected = 5,
});
final int minStagesBetween;
final Duration minInterval;
final int firstStagesProtected;
int _totalStagesCompleted = 0;
int _stagesSinceLastInterstitial = 0;
bool _rewardedShownThisRound = false;
DateTime? _lastInterstitialAt;
/// A new stage attempt began (fresh round). Clears the per-round rewarded
/// flag so last round's rewarded does not block this round's interstitial.
void onRoundStart() => _rewardedShownThisRound = false;
/// A stage finished (won or lost). Drives both counters.
void onStageCompleted() {
_totalStagesCompleted++;
_stagesSinceLastInterstitial++;
}
/// The player watched a rewarded ad in the current round.
void onRewardedShown() => _rewardedShownThisRound = true;
/// An interstitial was actually shown. Resets the spacing counters.
void onInterstitialShown(DateTime now) {
_stagesSinceLastInterstitial = 0;
_lastInterstitialAt = now;
}
bool canShowInterstitial(DateTime now) {
if (_totalStagesCompleted <= firstStagesProtected) return false;
if (_rewardedShownThisRound) return false;
if (_stagesSinceLastInterstitial < minStagesBetween) return false;
final last = _lastInterstitialAt;
if (last != null && now.difference(last) < minInterval) return false;
return true;
}
}