fa2784519b
- 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>
47 lines
1.6 KiB
Dart
47 lines
1.6 KiB
Dart
// 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();
|
||
}
|
||
}
|