feat(review): request a store review after a 3-star win, once
Adds an in-app review prompt gated by ReviewPromptPolicy: only after a 3-star stage win, once the player has cleared >=5 stages, at most once ever (persisted reviewRequested flag). ReviewService swallows all failures and only burns the one-shot when the store actually shows the sheet, so an unavailable store retries on a later win. StoreReviewer wraps in_app_review behind a Reviewer seam so unit tests skip platform channels. 13 new tests; full suite 194 green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -48,6 +48,9 @@ class SaveRepository {
|
||||
_musicEnabled =
|
||||
(json['flags'] as Map<String, dynamic>?)?['musicEnabled'] as bool? ??
|
||||
true;
|
||||
_reviewRequested = (json['flags']
|
||||
as Map<String, dynamic>?)?['reviewRequested'] as bool? ??
|
||||
false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +67,7 @@ class SaveRepository {
|
||||
bool _adsRemoved = false;
|
||||
bool _soundEnabled = true;
|
||||
bool _musicEnabled = true;
|
||||
bool _reviewRequested = false;
|
||||
|
||||
StreakState get streak => _streak;
|
||||
bool get tutorialDone => _tutorialDone;
|
||||
@@ -72,6 +76,14 @@ class SaveRepository {
|
||||
bool get soundEnabled => _soundEnabled;
|
||||
bool get musicEnabled => _musicEnabled;
|
||||
|
||||
/// Whether we've already asked the player for a store review (one-time).
|
||||
bool get reviewRequested => _reviewRequested;
|
||||
|
||||
/// Distinct stages the player has cleared (any season, >=1 star). Used to
|
||||
/// gate the review prompt behind a player who is clearly invested.
|
||||
int get stagesClearedCount =>
|
||||
_progress.values.where((p) => p.stars > 0).length;
|
||||
|
||||
Future<void> markTutorialDone() {
|
||||
_tutorialDone = true;
|
||||
return _flush();
|
||||
@@ -92,6 +104,11 @@ class SaveRepository {
|
||||
return _flush();
|
||||
}
|
||||
|
||||
Future<void> markReviewRequested() {
|
||||
_reviewRequested = true;
|
||||
return _flush();
|
||||
}
|
||||
|
||||
Future<void> recordEndlessScore(int score) {
|
||||
if (score > _endlessBest) _endlessBest = score;
|
||||
return _flush();
|
||||
@@ -165,6 +182,7 @@ class SaveRepository {
|
||||
'adsRemoved': _adsRemoved,
|
||||
'soundEnabled': _soundEnabled,
|
||||
'musicEnabled': _musicEnabled,
|
||||
'reviewRequested': _reviewRequested,
|
||||
},
|
||||
'endless': {'best': _endlessBest},
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user