calculateStreaks static method

StreakInfo calculateStreaks(
  1. List<DailyActivity> dailyActivity
)

Calculate current and longest streaks from daily activity data.

Implementation

static StreakInfo calculateStreaks(List<DailyActivity> dailyActivity) {
  if (dailyActivity.isEmpty) {
    return const StreakInfo();
  }

  final today = DateTime.now();
  final todayNorm = DateTime(today.year, today.month, today.day);

  final activeDates = dailyActivity.map((d) => d.date).toSet();

  // Calculate current streak (working backwards from today).
  var currentStreak = 0;
  String? currentStreakStart;
  var checkDate = todayNorm;

  while (true) {
    final dateStr = toDateString(checkDate);
    if (!activeDates.contains(dateStr)) break;
    currentStreak++;
    currentStreakStart = dateStr;
    checkDate = checkDate.subtract(const Duration(days: 1));
  }

  // Calculate longest streak.
  var longestStreak = 0;
  String? longestStreakStart;
  String? longestStreakEnd;

  final sortedDates = activeDates.toList()..sort();
  var tempStreak = 1;
  var tempStart = sortedDates.first;

  for (var i = 1; i < sortedDates.length; i++) {
    final prevDate = DateTime.parse(sortedDates[i - 1]);
    final currDate = DateTime.parse(sortedDates[i]);

    final dayDiff = currDate.difference(prevDate).inDays;

    if (dayDiff == 1) {
      tempStreak++;
    } else {
      if (tempStreak > longestStreak) {
        longestStreak = tempStreak;
        longestStreakStart = tempStart;
        longestStreakEnd = sortedDates[i - 1];
      }
      tempStreak = 1;
      tempStart = sortedDates[i];
    }
  }

  // Check final streak.
  if (tempStreak > longestStreak) {
    longestStreak = tempStreak;
    longestStreakStart = tempStart;
    longestStreakEnd = sortedDates.last;
  }

  return StreakInfo(
    currentStreak: currentStreak,
    longestStreak: longestStreak,
    currentStreakStart: currentStreakStart,
    longestStreakStart: longestStreakStart,
    longestStreakEnd: longestStreakEnd,
  );
}