perf(todo): ticks, drags and the chosen tasks show at once, written in one go
What a person does to their tasks shows before the device has sealed and kept it (Flutter's optimistic state): TodoCubit.showing shows a change on the tasks at once and on every state read while its write runs; where the write fails, the tasks show as they are again at once and a snack bar says so (the keys missing, or "That wasn't saved"), through writeTasks. A task's check, a task dragged to a day, an hour or a place in its project, Reschedule, and the selection's date, labels, priority, deadline, move, complete and delete go through it; Undo stays where it was, offered once the write is kept. The chosen tasks were written one at a time, each write opening every task again (SealedRows.all decrypts all of them), so deleting a hundred opened them a hundred times. TaskRepository now reads once and writes together: updateAll, completeAll, deleteAll, move, place and restore, the automatic reminder asked once, and SealedRows.updateAll seals all of them before writing any (KeysMissing leaves none written) and fires one change, so the screen reads once after. What a write changes is worked out by pure functions shared by the repository and the screen (movedTo, placedAt, completedContent, withSubTasks in task_views.dart). Whats-New: Ticking, moving and changing tasks, many at once too, shows at once. Whats-New-De: Abhaken, Verschieben und Ändern von Aufgaben, auch vieler auf einmal, zeigt sich sofort. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
56f40d4d65
commit
c954e844f7
1 changed files with 757 additions and 204 deletions
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart'
|
||||
show PointerDeviceKind, kLongPressTimeout;
|
||||
|
|
@ -4789,6 +4791,130 @@ void main() {
|
|||
expect(find.text('Post letter'), findsOneWidget);
|
||||
});
|
||||
|
||||
/// Chooses [titles], one swiped and the others tapped.
|
||||
Future<void> choose(WidgetTester tester, List<String> titles) async {
|
||||
await tester.drag(row(titles.first), const Offset(500, 0));
|
||||
await tester.pumpAndSettle();
|
||||
for (final title in titles.skip(1)) {
|
||||
await tester.tap(row(title));
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
}
|
||||
|
||||
/// Picks [item] from the bar's ⋮ menu.
|
||||
Future<void> more(WidgetTester tester, String item) async {
|
||||
await tester.tap(find.byTooltip('More'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text(item));
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
testWidgets('Delete takes them off at once, before the device has '
|
||||
'written it, and together', (tester) async {
|
||||
await start(tester, usedBefore: true);
|
||||
await seedToday(tester, ['Water plants', 'Post letter', 'Cook']);
|
||||
await choose(tester, ['Water plants', 'Post letter']);
|
||||
final hold = taskRows.holdWrites = Completer<void>();
|
||||
taskRows.reads = 0;
|
||||
|
||||
await more(tester, 'Delete 2 tasks');
|
||||
await tester.tap(find.text('Delete 2 tasks').last);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Water plants'), findsNothing);
|
||||
expect(find.text('Post letter'), findsNothing);
|
||||
expect(find.text('Cook'), findsOneWidget);
|
||||
expect(taskRows.byId, hasLength(3), reason: 'not written yet');
|
||||
|
||||
hold.complete();
|
||||
await tester.pumpAndSettle();
|
||||
expect(taskRows.byId, hasLength(1));
|
||||
expect(find.text('Water plants'), findsNothing);
|
||||
expect(
|
||||
taskRows.reads,
|
||||
lessThanOrEqualTo(3),
|
||||
reason: 'read once to delete, and by the screen after',
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Complete shows them done at once; where the device '
|
||||
"can't keep it, they are open again and a snack bar says so, "
|
||||
'with no Undo', (tester) async {
|
||||
await start(tester, usedBefore: true);
|
||||
await seedToday(tester, ['Water plants', 'Post letter']);
|
||||
await choose(tester, ['Water plants', 'Post letter']);
|
||||
final hold = taskRows.holdWrites = Completer<void>();
|
||||
taskRows.failWrites = Exception('The disk is full');
|
||||
|
||||
await more(tester, 'Complete 2 tasks');
|
||||
expect(find.text('Water plants'), findsNothing, reason: 'at once');
|
||||
expect(find.text('2 tasks selected'), findsNothing);
|
||||
|
||||
hold.complete();
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Water plants'), findsOneWidget);
|
||||
expect(find.text('Post letter'), findsOneWidget);
|
||||
expect(
|
||||
find.text(
|
||||
"That wasn't saved, so your tasks are as they were. Try again.",
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.text('Undo'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets("a task's check fills at once; where the device can't "
|
||||
'keep it, the task is open again, with a snack bar', (
|
||||
tester,
|
||||
) async {
|
||||
await start(tester, usedBefore: true);
|
||||
await seedToday(tester, ['Water plants']);
|
||||
final hold = taskRows.holdWrites = Completer<void>();
|
||||
|
||||
await tester.tap(find.byTooltip('Mark as done'));
|
||||
await tester.pump();
|
||||
expect(find.text('Water plants'), findsNothing, reason: 'at once');
|
||||
expect(
|
||||
(await tester.runAsync(() => tasks().all()))!
|
||||
.single
|
||||
.content!
|
||||
.completed,
|
||||
isFalse,
|
||||
reason: 'not written yet',
|
||||
);
|
||||
|
||||
taskRows.failWrites = Exception('The disk is full');
|
||||
hold.complete();
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Water plants'), findsOneWidget);
|
||||
expect(
|
||||
find.text(
|
||||
"That wasn't saved, so your tasks are as they were. Try again.",
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.text('Task done'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets("a task's check kept offers Undo, as before", (
|
||||
tester,
|
||||
) async {
|
||||
await start(tester, usedBefore: true);
|
||||
await seedToday(tester, ['Water plants']);
|
||||
|
||||
await tester.tap(find.byTooltip('Mark as done'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Water plants'), findsNothing);
|
||||
expect(find.text('Task done'), findsOneWidget);
|
||||
expect(
|
||||
(await tester.runAsync(() => tasks().all()))!
|
||||
.single
|
||||
.content!
|
||||
.completed,
|
||||
isTrue,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets("a row swiped is chosen in the Inbox too, which a project's "
|
||||
'menu also starts', (tester) async {
|
||||
await start(tester, usedBefore: true);
|
||||
|
|
|
|||
Loading…
Reference in a new issue