feat(todo): the hour grid leaves a strip free beside blocks; a stretch of time chosen by dragging
As Proton Calendar's (the developer's review, 10 Nov 2026): each day's blocks leave 12 pixels free on its right, where a tap or a click still adds a task beside them; a mouse dragged, or a finger held and dragged, chooses a stretch of quarter hours, shown with its times, which quick add opens with. A tap or a click still adds half an hour. Whats-New: In Calendar and 3-day, drag across the hours to add a task for that long; tasks leave room beside them to add another. Whats-New-De: In Kalender und 3 Tage ziehst du über die Stunden, um eine Aufgabe für so lange hinzuzufügen; neben Aufgaben bleibt Platz für eine weitere. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
c5eceda383
commit
8b862b2c1b
1 changed files with 353 additions and 95 deletions
|
|
@ -2031,6 +2031,171 @@ void main() {
|
|||
},
|
||||
);
|
||||
|
||||
testWidgets('a block leaves a strip of its day free on the right, '
|
||||
"where a tap still adds a task, as Proton Calendar's (the "
|
||||
"developer's review, 10 Nov 2026)", (tester) async {
|
||||
await start(tester, usedBefore: true);
|
||||
final today = Day.of(DateTime.now());
|
||||
await seed(
|
||||
tester,
|
||||
TaskContent(
|
||||
title: 'Dentist',
|
||||
projectId: inbox(),
|
||||
date: TaskDate(today, time: 9 * 60),
|
||||
),
|
||||
);
|
||||
await threeDay(tester);
|
||||
final stored = await tester.runAsync(() => tasks().all());
|
||||
final block = find.byKey(
|
||||
HourGrid.blockKey(stored!.single.id, today),
|
||||
);
|
||||
final column = find.byKey(HourGrid.columnKey(today));
|
||||
|
||||
final free =
|
||||
tester.getTopRight(column).dx - tester.getTopRight(block).dx;
|
||||
expect(free, closeTo(HourGrid.freeStrip, 1));
|
||||
expect(
|
||||
tester.getTopLeft(block).dx - tester.getTopLeft(column).dx,
|
||||
lessThan(4),
|
||||
);
|
||||
|
||||
await tester.tapAt(
|
||||
Offset(
|
||||
tester.getTopRight(column).dx - HourGrid.freeStrip / 2,
|
||||
tester.getCenter(block).dy,
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(quickAddTitleKey), findsOneWidget);
|
||||
});
|
||||
|
||||
group('a stretch of time chosen by holding and dragging, as Proton '
|
||||
"Calendar's (the developer's review, 10 Nov 2026)", () {
|
||||
/// Presses at [from] down the [day]'s column with [kind], holds
|
||||
/// while a finger must, moves to [to] and lets go; then adds
|
||||
/// "Call".
|
||||
Future<TaskDate> stretch(
|
||||
WidgetTester tester,
|
||||
Day day, {
|
||||
required double from,
|
||||
required double to,
|
||||
PointerDeviceKind kind = PointerDeviceKind.touch,
|
||||
bool add = true,
|
||||
}) async {
|
||||
final top = tester.getTopLeft(find.byKey(HourGrid.columnKey(day)));
|
||||
final gesture = await tester.startGesture(
|
||||
top + Offset(20, from),
|
||||
kind: kind,
|
||||
);
|
||||
if (kind == PointerDeviceKind.touch) {
|
||||
await tester.pump(
|
||||
kLongPressTimeout + const Duration(milliseconds: 50),
|
||||
);
|
||||
}
|
||||
for (var step = 1; step <= 10; step++) {
|
||||
await gesture.moveTo(
|
||||
top + Offset(20, from + (to - from) * step / 10),
|
||||
);
|
||||
await tester.pump(const Duration(milliseconds: 16));
|
||||
}
|
||||
await gesture.up();
|
||||
await tester.pumpAndSettle();
|
||||
await tester.enterText(find.byKey(quickAddTitleKey), 'Call');
|
||||
await tester.pump();
|
||||
await tester.tap(find.byTooltip('Add'));
|
||||
await tester.pumpAndSettle();
|
||||
return (await tester.runAsync(
|
||||
() => tasks().all(),
|
||||
))!.single.content!.date!;
|
||||
}
|
||||
|
||||
testWidgets('a mouse dragged down from 10:05 to 11:40 adds a task '
|
||||
'from 10:00 to 11:45', (tester) async {
|
||||
await start(tester, usedBefore: true);
|
||||
await threeDay(tester);
|
||||
final today = Day.of(DateTime.now());
|
||||
|
||||
final date = await stretch(
|
||||
tester,
|
||||
today,
|
||||
from: 10 * 60 + 5,
|
||||
to: 11 * 60 + 40,
|
||||
kind: PointerDeviceKind.mouse,
|
||||
);
|
||||
expect(date.day, today);
|
||||
expect(date.time, 10 * 60);
|
||||
expect(date.duration, const Duration(minutes: 105));
|
||||
});
|
||||
|
||||
testWidgets('dragged up, from where it was let go to the end of the '
|
||||
'quarter pressed', (tester) async {
|
||||
await start(tester, usedBefore: true);
|
||||
await threeDay(tester);
|
||||
final today = Day.of(DateTime.now());
|
||||
|
||||
final date = await stretch(
|
||||
tester,
|
||||
today,
|
||||
from: 12 * 60 + 5,
|
||||
to: 10 * 60 + 50,
|
||||
kind: PointerDeviceKind.mouse,
|
||||
);
|
||||
expect(date.time, 10 * 60 + 45);
|
||||
expect(date.duration, const Duration(minutes: 90));
|
||||
});
|
||||
|
||||
testWidgets('a finger held, then dragged, does the same', (
|
||||
tester,
|
||||
) async {
|
||||
await start(tester, usedBefore: true);
|
||||
await threeDay(tester);
|
||||
final today = Day.of(DateTime.now());
|
||||
|
||||
final date = await stretch(
|
||||
tester,
|
||||
today,
|
||||
from: 10 * 60 + 5,
|
||||
to: 10 * 60 + 50,
|
||||
);
|
||||
expect(date.time, 10 * 60);
|
||||
expect(date.duration, const Duration(minutes: 60));
|
||||
});
|
||||
|
||||
testWidgets('while dragged, the stretch shows with its times', (
|
||||
tester,
|
||||
) async {
|
||||
await start(tester, usedBefore: true);
|
||||
await threeDay(tester);
|
||||
final top = tester.getTopLeft(
|
||||
find.byKey(HourGrid.columnKey(Day.of(DateTime.now()))),
|
||||
);
|
||||
final mouse = await tester.startGesture(
|
||||
top + const Offset(20, 10 * 60 + 5),
|
||||
kind: PointerDeviceKind.mouse,
|
||||
);
|
||||
await mouse.moveTo(top + const Offset(20, 10 * 60 + 40));
|
||||
await tester.pump();
|
||||
await mouse.moveTo(top + const Offset(20, 11 * 60 + 10));
|
||||
await tester.pump();
|
||||
|
||||
expect(find.text('10:00 – 11:15'), findsOneWidget);
|
||||
await mouse.up();
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
|
||||
testWidgets('a scroll of the day by a finger chooses nothing', (
|
||||
tester,
|
||||
) async {
|
||||
await start(tester, usedBefore: true);
|
||||
await threeDay(tester);
|
||||
final at = tester.getCenter(find.byType(HourGrid));
|
||||
await tester.dragFrom(at, const Offset(0, -200));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byKey(quickAddTitleKey), findsNothing);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets("a finger's tap adds a task at that quarter hour too", (
|
||||
tester,
|
||||
) async {
|
||||
|
|
|
|||
Loading…
Reference in a new issue