Files
BlockSeasons/lib/state/daily_reward_notifier.dart
T
airkjw fa2784519b fix(boosters): address final-review findings
- daily claim: record the claim before granting boosters, so a crash
  mid-claim forfeits at most one reward instead of allowing a re-claim
  (booster farming) on next launch.
- game screen: disarm the booster target synchronously before awaiting,
  so a rapid second board tap can't double-fire a use or stack a dialog.
- new players: seed one of each booster once (idempotent persisted flag),
  fulfilling the spec's starting inventory. Wired in main().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 19:36:24 +09:00

47 lines
1.6 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// lib/state/daily_reward_notifier.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../data/save_repository.dart';
import '../game/daily/daily_reward.dart';
import 'providers.dart';
class DailyRewardNotifier extends Notifier<DailyResolution> {
static const _cal = DailyRewardCalendar();
SaveRepository get _save => ref.read(saveRepositoryProvider);
DateTime Function() get _now => ref.read(dailyNowProvider);
@override
DailyResolution build() => _resolve();
DailyResolution _resolve() => _cal.resolve(
lastClaimedYmd: _save.dailyLastClaimedYmd,
storedDay: _save.dailyCalendarDay,
today: _now(),
);
/// Grants the current day's reward (×2 if [doubled]) and records the claim.
Future<void> claim({bool doubled = false}) async {
final r = state;
if (!r.claimable) return;
final reward = _cal.rewardFor(r.day);
// Record the claim BEFORE granting, so a crash mid-claim forfeits at most
// one reward rather than leaving the day unrecorded (which would let the
// player re-claim and farm boosters on the next launch).
await _save.recordDailyClaim(_cal.ymd(_now()), r.day);
final inv = ref.read(boosterInventoryProvider.notifier);
for (final entry in reward.entries) {
await inv.grant(entry.key, entry.value * (doubled ? 2 : 1));
}
ref.read(analyticsProvider).dailyRewardClaimed(day: r.day, doubled: doubled);
for (final e in reward.entries) {
ref.read(analyticsProvider).boosterGranted(
type: e.key.name,
count: e.value * (doubled ? 2 : 1),
source: 'daily',
);
}
state = _resolve();
}
}