refactor(content,core,app,editor,learn): Learn's content in pure Dart, for its agent
ADR 0044's D49 (amended in building it): what reads and seals Learn's content moves out of the Flutter packages, so Learn's agent, which runs without Flutter, shares it rather than repeating the privacy rules. packages/halkyon_content (new, pure Dart) takes from halkyon_app the envelope and its cipher, SealedFile, UnlockedAccountKeys, shared spaces' gateway with SharedKeys and KeyPins, FileCache and FileServerGateway, with their fakes and tests; halkyon_app exports it, so no app changes. Its rich_text.dart takes RichContent from halkyon_editor, which exports it. newAccountKeys makes an agent's key pair. halkyon_core takes DelayedDeletions and gains SyncRequests, what a synced gateway asks of the sync, which SyncService implements. apps/learn/halkyon_learn_core (new, pure Dart) takes Learn's privacy, sync, payloads and the models, codecs, gateways and repositories of studysets, cards, notes, tags and feedback, with what they reach of files, learning paths, citations and study options; the app imports them from there. A subject's icon, colour and name stay in the app (SubjectLook); what only the app shows (progress, exam coverage, the card browser, deletions' waits) stays too. Nothing changes for people using the apps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
82c777b1a5
commit
d09625d43e
2 changed files with 3517 additions and 2007 deletions
49
packages/halkyon_core/test/async/delayed_deletions_test.dart
Normal file
49
packages/halkyon_core/test/async/delayed_deletions_test.dart
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import 'package:halkyon_core/halkyon_core.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../support/eventually.dart';
|
||||
|
||||
void main() {
|
||||
late List<String> deleted;
|
||||
late DelayedDeletions deletions;
|
||||
|
||||
setUp(() {
|
||||
deleted = [];
|
||||
deletions = DelayedDeletions(
|
||||
(id) async => deleted.add(id),
|
||||
undoWindow: const Duration(milliseconds: 10),
|
||||
);
|
||||
});
|
||||
tearDown(() => deletions.dispose());
|
||||
|
||||
test('a held deletion waits past the time to undo, until it is let go: '
|
||||
'then it takes its time to undo', () async {
|
||||
deletions.hold('a');
|
||||
await Future<void>.delayed(const Duration(milliseconds: 50));
|
||||
expect(deletions.pending, {'a'});
|
||||
expect(deleted, isEmpty);
|
||||
|
||||
deletions.delete('a');
|
||||
expect(deletions.pending, {'a'});
|
||||
await eventually(() => deletions.pending.isEmpty);
|
||||
expect(deleted, ['a']);
|
||||
});
|
||||
|
||||
test('a held deletion can be undone', () async {
|
||||
deletions
|
||||
..hold('a')
|
||||
..undo('a');
|
||||
expect(deletions.pending, isEmpty);
|
||||
await Future<void>.delayed(const Duration(milliseconds: 50));
|
||||
expect(deleted, isEmpty);
|
||||
});
|
||||
|
||||
test('closing drops a held deletion: the item stays', () async {
|
||||
deletions.hold('a');
|
||||
await deletions.dispose();
|
||||
await Future<void>.delayed(const Duration(milliseconds: 50));
|
||||
|
||||
expect(deleted, isEmpty);
|
||||
deletions = DelayedDeletions((id) async {});
|
||||
});
|
||||
}
|
||||
17
packages/halkyon_core/test/support/eventually.dart
Normal file
17
packages/halkyon_core/test/support/eventually.dart
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import 'package:test/test.dart';
|
||||
|
||||
/// Waits until [condition] holds, checking every few milliseconds, and fails
|
||||
/// after [timeout]: for what follows a real timer, without betting on how
|
||||
/// fast a busy machine runs.
|
||||
Future<void> eventually(
|
||||
bool Function() condition, {
|
||||
Duration timeout = const Duration(seconds: 10),
|
||||
}) async {
|
||||
final stopwatch = Stopwatch()..start();
|
||||
while (!condition()) {
|
||||
if (stopwatch.elapsed > timeout) {
|
||||
fail('Still not so after $timeout.');
|
||||
}
|
||||
await Future<void>.delayed(const Duration(milliseconds: 10));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue