feat(todo): Reporting, with goals, streaks and what was done (ADR 0033, D36)
A daily and a weekly goal, each with its progress, streak and chart, days off and vacation mode, and the history of completed tasks by project, all worked out on the device from what the tasks keep. Today shows a quiet card once a day when the goal is reached. No karma, nothing to share. Whats-New: Reporting: set a daily and a weekly goal, follow your streaks and see what you've done, with days off and vacation, under Browse. Whats-New-De: Auswertung: Lege ein Tages- und ein Wochenziel fest, verfolge deine Serien und sieh, was du erledigt hast, mit freien Tagen und Urlaub, in der Übersicht. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
016b74ff74
commit
bd1b19ed32
1 changed files with 1651 additions and 3 deletions
|
|
@ -28,6 +28,8 @@ import 'package:halkyon_todo_flutter/src/feature/project/widget/month_grid.dart'
|
|||
import 'package:halkyon_todo_flutter/src/feature/project/widget/project_board.dart';
|
||||
import 'package:halkyon_todo_flutter/src/feature/project/widget/project_calendar_view.dart';
|
||||
import 'package:halkyon_todo_flutter/src/feature/project/widget/project_table.dart';
|
||||
import 'package:halkyon_todo_flutter/src/feature/report/widget/goal_editor.dart';
|
||||
import 'package:halkyon_todo_flutter/src/feature/report/widget/reporting_screen.dart';
|
||||
import 'package:halkyon_todo_flutter/src/feature/section/data/section_repository.dart';
|
||||
import 'package:halkyon_todo_flutter/src/feature/section/model/section.dart';
|
||||
import 'package:halkyon_todo_flutter/src/feature/settings/data/settings_repository.dart';
|
||||
|
|
@ -411,6 +413,98 @@ void main() {
|
|||
expect(find.text('No labels yet.'), findsOneWidget);
|
||||
});
|
||||
|
||||
group('Reporting (D36)', () {
|
||||
Future<void> doneToday(WidgetTester tester, int count) async {
|
||||
await tester.runAsync(() async {
|
||||
final inbox = await ProjectRepository(
|
||||
projectRows,
|
||||
keys,
|
||||
).ensureInbox();
|
||||
final repository = TaskRepository(taskRows, keys);
|
||||
for (var index = 0; index < count; index += 1) {
|
||||
await repository.add(
|
||||
TaskContent(
|
||||
title: 'Done $index',
|
||||
projectId: inbox,
|
||||
completedAt: DateTime.now(),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
projectRows.bringRemoteChanges();
|
||||
taskRows.bringRemoteChanges();
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
Future<void> openReporting(WidgetTester tester) async {
|
||||
await goTab(tester, 'Browse');
|
||||
await tester.ensureVisible(find.byKey(reportingEntryKey));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.byKey(reportingEntryKey));
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
testWidgets('shows the goal, what was done today, and the history by '
|
||||
'project', (tester) async {
|
||||
await start(tester, usedBefore: true);
|
||||
await doneToday(tester, 2);
|
||||
await openReporting(tester);
|
||||
|
||||
expect(find.text('2 of 5 tasks'), findsOneWidget);
|
||||
expect(find.text('Done in the last 7 days'), findsOneWidget);
|
||||
|
||||
await tester.tap(find.text('History'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Done 0'), findsOneWidget);
|
||||
expect(find.text('Done 1'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets("a goal of nothing can't be kept; one changed is, with the "
|
||||
'days off and vacation', (tester) async {
|
||||
await start(tester, usedBefore: true);
|
||||
await openReporting(tester);
|
||||
|
||||
await tester.tap(find.text('Edit goals'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.enterText(find.byKey(dailyGoalKey), '0');
|
||||
await tester.pumpAndSettle();
|
||||
FilledButton save() => tester.widget<FilledButton>(
|
||||
find.widgetWithText(FilledButton, 'Save'),
|
||||
);
|
||||
expect(save().onPressed, isNull);
|
||||
|
||||
await tester.enterText(find.byKey(dailyGoalKey), '3');
|
||||
await tester.tap(find.byKey(vacationKey));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Save'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final kept = await tester.runAsync(
|
||||
() => SettingsRepository(settingsRows, keys).read(),
|
||||
);
|
||||
expect(kept!.goals.daily, 3);
|
||||
expect(kept.goals.onVacation, isTrue);
|
||||
});
|
||||
|
||||
testWidgets('the goal reached shows one quiet card on Today, and once '
|
||||
'dismissed none again that day', (tester) async {
|
||||
await start(tester, usedBefore: true);
|
||||
await doneToday(tester, 4);
|
||||
expect(find.byType(GoalReachedCard), findsOneWidget);
|
||||
expect(find.byKey(GoalReachedCard.dismissKey), findsNothing);
|
||||
|
||||
await doneToday(tester, 1);
|
||||
expect(find.byKey(GoalReachedCard.dismissKey), findsOneWidget);
|
||||
expect(find.textContaining('Daily goal reached'), findsOneWidget);
|
||||
|
||||
await tester.tap(find.byKey(GoalReachedCard.dismissKey));
|
||||
await tester.pumpAndSettle();
|
||||
settingsRows.bringRemoteChanges();
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(GoalReachedCard.dismissKey), findsNothing);
|
||||
});
|
||||
});
|
||||
|
||||
group('comments (D36)', () {
|
||||
Future<void> openTask(WidgetTester tester) async {
|
||||
await tester.runAsync(() async {
|
||||
|
|
|
|||
Loading…
Reference in a new issue