49 lines
1.5 KiB
Dart
49 lines
1.5 KiB
Dart
/// Month-grid helpers for the shop-log heatmap.
|
||
library;
|
||
|
||
DateTime dateOnly(DateTime date) => DateTime(date.year, date.month, date.day);
|
||
|
||
DateTime monthStart(DateTime date) => DateTime(date.year, date.month);
|
||
|
||
bool isSameDay(DateTime a, DateTime b) =>
|
||
a.year == b.year && a.month == b.month && a.day == b.day;
|
||
|
||
bool isSameMonth(DateTime a, DateTime b) =>
|
||
a.year == b.year && a.month == b.month;
|
||
|
||
DateTime addMonths(DateTime month, int delta) =>
|
||
DateTime(month.year, month.month + delta);
|
||
|
||
/// Monday-first calendar cells for [month], padded with nulls to full weeks.
|
||
List<DateTime?> monthGrid(DateTime month) {
|
||
final start = DateTime(month.year, month.month, 1);
|
||
final daysInMonth = DateTime(month.year, month.month + 1, 0).day;
|
||
final leading = start.weekday - DateTime.monday;
|
||
final cells = <DateTime?>[
|
||
...List<DateTime?>.filled(leading, null),
|
||
for (var day = 1; day <= daysInMonth; day++)
|
||
DateTime(month.year, month.month, day),
|
||
];
|
||
while (cells.length % 7 != 0) {
|
||
cells.add(null);
|
||
}
|
||
return cells;
|
||
}
|
||
|
||
/// How many trips landed on each calendar day.
|
||
Map<DateTime, int> tripCountsByDay(Iterable<DateTime> shoppedAt) {
|
||
final counts = <DateTime, int>{};
|
||
for (final date in shoppedAt) {
|
||
final key = dateOnly(date);
|
||
counts[key] = (counts[key] ?? 0) + 1;
|
||
}
|
||
return counts;
|
||
}
|
||
|
||
/// GitHub-style 0–4 intensity from a trip count.
|
||
int heatmapLevel(int count) {
|
||
if (count <= 0) return 0;
|
||
if (count >= 4) return 4;
|
||
return count;
|
||
}
|