101 lines
3 KiB
Dart
101 lines
3 KiB
Dart
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
|
|
import 'package:timetrack/features/reports/data/drift_reports_repository.dart';
|
|
import 'package:timetrack/features/reports/data/reports_repository.dart';
|
|
import 'package:timetrack/features/reports/domain/report_data.dart';
|
|
|
|
part 'reports_provider.g.dart';
|
|
|
|
@riverpod
|
|
class ReportsNotifier extends _$ReportsNotifier {
|
|
@override
|
|
Future<ReportData> build() => _loadData();
|
|
|
|
ReportPeriod _period = ReportPeriod.week;
|
|
DateTime _anchor = DateTime.now();
|
|
int? _filterProjectId;
|
|
|
|
ReportsRepository get _repo => ref.read(reportsRepositoryProvider);
|
|
|
|
ReportPeriod get period => _period;
|
|
|
|
void selectPeriod(ReportPeriod period) {
|
|
_period = period;
|
|
_anchor = DateTime.now();
|
|
ref.invalidateSelf();
|
|
}
|
|
|
|
void goToPrevious() {
|
|
_anchor = _shift(-1);
|
|
ref.invalidateSelf();
|
|
}
|
|
|
|
void goToNext() {
|
|
_anchor = _shift(1);
|
|
ref.invalidateSelf();
|
|
}
|
|
|
|
void filterByProject(int? projectId) {
|
|
_filterProjectId = projectId;
|
|
ref.invalidateSelf();
|
|
}
|
|
|
|
DateTime _shift(int direction) {
|
|
switch (_period) {
|
|
case ReportPeriod.day:
|
|
return _anchor.add(Duration(days: direction));
|
|
case ReportPeriod.week:
|
|
return _anchor.add(Duration(days: 7 * direction));
|
|
case ReportPeriod.month:
|
|
return DateTime(_anchor.year, _anchor.month + direction);
|
|
}
|
|
}
|
|
|
|
(DateTime, DateTime) _periodBounds() {
|
|
switch (_period) {
|
|
case ReportPeriod.day:
|
|
final start = DateTime(_anchor.year, _anchor.month, _anchor.day);
|
|
return (start, start.add(const Duration(days: 1)));
|
|
case ReportPeriod.week:
|
|
final monday = _anchor.subtract(Duration(days: _anchor.weekday - 1));
|
|
final start = DateTime(monday.year, monday.month, monday.day);
|
|
return (start, start.add(const Duration(days: 7)));
|
|
case ReportPeriod.month:
|
|
final start = DateTime(_anchor.year, _anchor.month);
|
|
return (start, DateTime(_anchor.year, _anchor.month + 1));
|
|
}
|
|
}
|
|
|
|
Future<ReportData> _loadData() async {
|
|
final (from, to) = _periodBounds();
|
|
final total = await _repo.getTotalDuration(from, to, projectId: _filterProjectId);
|
|
final byProject = await _repo.getDurationByProject(from, to);
|
|
|
|
final List<double> chartValues;
|
|
switch (_period) {
|
|
case ReportPeriod.day:
|
|
chartValues = List.filled(24, 0.0);
|
|
break;
|
|
case ReportPeriod.week:
|
|
final byDay = await _repo.getDurationByWeekday(from);
|
|
chartValues = List.generate(7, (i) => (byDay[i]?.inMinutes ?? 0).toDouble());
|
|
break;
|
|
case ReportPeriod.month:
|
|
final byDay = await _repo.getDurationByDay(from);
|
|
final daysInMonth = to.difference(from).inDays;
|
|
chartValues = List.generate(
|
|
daysInMonth,
|
|
(i) => (byDay[i + 1]?.inMinutes ?? 0).toDouble(),
|
|
);
|
|
break;
|
|
}
|
|
|
|
return ReportData(
|
|
totalDuration: total,
|
|
durationByProject: byProject,
|
|
chartValues: chartValues,
|
|
periodStart: from,
|
|
periodEnd: to,
|
|
);
|
|
}
|
|
}
|