feat(todo): the Inbox's Calendar as an Agenda or 3-day

As Todoist's Display in the Inbox: once its layout is Calendar, a row
"Layout: Agenda" opens a small choice of Agenda or 3-day; 3-day shows the
Inbox's tasks in Upcoming's HourGrid, whatever the window's width, where a
tap on an hour adds to the Inbox. Kept as the project's other Display
choices, in its sealed view (`calendarLayout`, written only when it isn't
the Agenda; a value this version doesn't know reads as the Agenda).
Another project's Calendar stays the agenda (or the month), as Todoist
offers the choice in the Inbox alone.

Whats-New: The Inbox's Calendar can show three days of hours: Display, Layout, 3-day.
Whats-New-De: Der Kalender des Eingangs kann drei Tage mit ihren Stunden zeigen: Anzeige, Layout, 3 Tage.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-11-07 22:59:46 +01:00
commit 71b5337d21
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -28,6 +28,7 @@ import 'package:halkyon_todo_flutter/src/feature/project/data/project_repository
import 'package:halkyon_todo_flutter/src/feature/project/model/project.dart';
import 'package:halkyon_todo_flutter/src/feature/project/model/project_view.dart';
import 'package:halkyon_todo_flutter/src/feature/project/model/stored_project.dart';
import 'package:halkyon_todo_flutter/src/feature/project/widget/display_sheet.dart';
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';
@ -1585,6 +1586,87 @@ void main() {
expect(find.byTooltip('Mark as done'), findsOneWidget);
});
testWidgets("the Inbox's Calendar is an Agenda or 3-day, as its "
'Display picks, kept in the Inbox; another project offers '
"neither (the developer's review, 7 Nov 2026, as Todoist's)", (
tester,
) async {
await calendarOf(tester);
await seed(
tester,
TaskContent(
title: 'Dentist',
projectId: inbox(),
date: TaskDate(Day.of(DateTime.now()), time: 10 * 60),
),
);
expect(find.byType(WeekStrip), findsOneWidget);
await display(tester);
expect(
find.descendant(
of: find.byKey(calendarLayoutKey),
matching: find.text('Agenda'),
),
findsOneWidget,
);
await tester.tap(find.byKey(calendarLayoutKey));
await tester.pumpAndSettle();
await tester.tap(find.widgetWithText(ListTile, '3-day').last);
await tester.pumpAndSettle();
expect(
find.descendant(
of: find.byKey(calendarLayoutKey),
matching: find.text('3-day'),
),
findsOneWidget,
);
await done(tester);
expect(find.byType(HourGrid), findsOneWidget);
expect(find.byType(WeekStrip), findsNothing);
expect(
find.descendant(
of: find.byType(HourGrid),
matching: find.text('Dentist'),
),
findsOneWidget,
);
final projects = await tester.runAsync(
() => ProjectRepository(projectRows, keys).all(),
);
expect(
projects!
.singleWhere((project) => project.id == inbox())
.content
?.view
.calendarLayout,
CalendarLayout.threeDay,
);
// A project of its own: its Calendar is the agenda alone.
await tester.runAsync(
() => ProjectRepository(projectRows, keys).save(
const ProjectContent(
name: 'Shopping',
position: 1,
view: ProjectView(
layout: ProjectLayout.calendar,
calendarLayout: CalendarLayout.threeDay,
),
),
),
);
projectRows.bringRemoteChanges();
await goTab(tester, 'Browse');
await tester.tap(find.text('Shopping'));
await tester.pumpAndSettle();
expect(find.byType(WeekStrip), findsOneWidget);
expect(find.byType(HourGrid), findsNothing);
await display(tester);
expect(find.byKey(calendarLayoutKey), findsNothing);
});
group('as a month on a wide window', () {
/// Another day of today's month, so in its grid.
Day otherDay() {