Add daily streak system and normalize bundle id to com.airkjw.blockseasons
Pure advanceStreak (1-day grace none, milestone flags at 3/7/14/30), persisted in the save blob; StreakNotifier advances on every finished attempt; home screen flame chip and milestone snackbar. Fix flutter create's camelCased iOS bundle id and underscored Android application id to the agreed lowercase form before any store registration. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
/// Daily streak: at least one stage attempt (win or lose) per local
|
||||
/// calendar day keeps it alive. No clock-cheat defense — single-player,
|
||||
/// low stakes.
|
||||
class StreakState {
|
||||
const StreakState({
|
||||
required this.current,
|
||||
required this.best,
|
||||
required this.lastYmd,
|
||||
this.hitMilestone,
|
||||
});
|
||||
|
||||
static const initial = StreakState(current: 0, best: 0, lastYmd: null);
|
||||
|
||||
static const milestones = [3, 7, 14, 30];
|
||||
|
||||
final int current;
|
||||
final int best;
|
||||
|
||||
/// Local date of the last counted play, as `yyyy-MM-dd`.
|
||||
final String? lastYmd;
|
||||
|
||||
/// Set when this advance just reached a milestone (celebrate once).
|
||||
final int? hitMilestone;
|
||||
}
|
||||
|
||||
String _ymd(DateTime d) =>
|
||||
'${d.year.toString().padLeft(4, '0')}-'
|
||||
'${d.month.toString().padLeft(2, '0')}-'
|
||||
'${d.day.toString().padLeft(2, '0')}';
|
||||
|
||||
StreakState advanceStreak(StreakState state, DateTime now) {
|
||||
final today = _ymd(now);
|
||||
if (state.lastYmd == today) {
|
||||
return StreakState(
|
||||
current: state.current,
|
||||
best: state.best,
|
||||
lastYmd: today,
|
||||
);
|
||||
}
|
||||
// Normalized constructor handles month/year boundaries (and DST).
|
||||
final yesterday = _ymd(DateTime(now.year, now.month, now.day - 1));
|
||||
final current = state.lastYmd == yesterday ? state.current + 1 : 1;
|
||||
return StreakState(
|
||||
current: current,
|
||||
best: current > state.best ? current : state.best,
|
||||
lastYmd: today,
|
||||
hitMilestone: StreakState.milestones.contains(current) ? current : null,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user