refactor(learn): the editor's general parts move to halkyon_editor (ADR 0033, D37)

Todo stores editor documents too, so the document, the editor, its view,
the format bar, links, the clipboard, scripts and EditorBlocks move, with
their strings and tests, to a shared package on the same appflowy_editor
fork. What is Learn's alone stays in Learn on top of it, and what the
editor took from it directly is inverted: EditorBlocks gains textMarks,
formatActions and onEditorClosed, RichContentEditor a wrapEditor, and an
InsertableBlock's name takes the BuildContext. Learn's screens use
LearnContentEditor and LearnContentView, which add Learn's blocks and the
grammar check. Learn behaves as before.

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-06 21:25:44 +01:00
commit 648dfe4051
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
74 changed files with 1676 additions and 1366 deletions

View file

@ -1,5 +1,5 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/feature/anki/data/anki_field.dart';
void main() {

View file

@ -2,7 +2,7 @@ import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/testing.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/router/route_paths.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_repository.dart';
import 'package:halkyon_learn_flutter/src/feature/note/data/note_repository.dart';

View file

@ -3,11 +3,10 @@ import 'dart:typed_data';
import 'package:clock/clock.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
import 'package:halkyon_learn_flutter/src/core/asset/model/stored_file.dart';
import 'package:halkyon_learn_flutter/src/core/content/content_blocks.dart';
import 'package:halkyon_learn_flutter/src/core/content/published_ref.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_learn_flutter/src/feature/archive/data/archive_exporter.dart';
import 'package:halkyon_learn_flutter/src/feature/archive/data/archive_importer.dart';
import 'package:halkyon_learn_flutter/src/feature/archive/data/archive_reader.dart';

View file

@ -3,9 +3,8 @@ import 'dart:typed_data';
import 'package:archive/archive.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
import 'package:halkyon_learn_flutter/src/core/content/content_blocks.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_learn_flutter/src/feature/archive/data/archive_importer.dart';
import 'package:halkyon_learn_flutter/src/feature/archive/data/archive_reader.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_payload.dart';

View file

@ -1,7 +1,7 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/testing.dart' show FakeSpeechInput;
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/device_settings/model/device_settings.dart';
import 'package:halkyon_learn_flutter/src/core/router/route_paths.dart';
import 'package:halkyon_learn_flutter/src/feature/assistant/data/web_search.dart';

View file

@ -4,7 +4,7 @@ import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/halkyon_app.dart';
import 'package:halkyon_app/testing.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/feature/assistant/bloc/conversation_cubit.dart';
import 'package:halkyon_learn_flutter/src/feature/assistant/data/assistant_lookups.dart';
import 'package:halkyon_learn_flutter/src/feature/assistant/data/conversation_repository.dart';

View file

@ -4,8 +4,8 @@ import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/halkyon_app.dart';
import 'package:halkyon_app/testing.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_learn_flutter/src/core/router/route_paths.dart';
import 'package:halkyon_learn_flutter/src/feature/assistant/bloc/card_proposals_cubit.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_payload.dart';

View file

@ -4,8 +4,8 @@ import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/halkyon_app.dart';
import 'package:halkyon_app/testing.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/asset/data/asset_repository.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_learn_flutter/src/core/device_settings/model/device_settings.dart';
import 'package:halkyon_learn_flutter/src/core/grammar/grammar_match.dart';
import 'package:halkyon_learn_flutter/src/core/router/route_paths.dart';

View file

@ -2,7 +2,7 @@ import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/feature/assistant/data/assistant_lookups.dart';
import 'package:halkyon_learn_flutter/src/feature/assistant/model/assistant_conversation.dart';
import 'package:halkyon_learn_flutter/src/feature/assistant/model/assistant_lookup.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/feature/card/bloc/card_list_bloc.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_deletions.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_repository.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/feature/card/bloc/card_browser_bloc.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_deletions.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_repository.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/feature/card/bloc/card_composer_bloc.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_payload.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_repository.dart';

View file

@ -2,8 +2,8 @@ import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/content/payload.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_payload.dart';
import 'package:halkyon_learn_flutter/src/feature/card/model/card_content.dart';

View file

@ -2,9 +2,9 @@ import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/content/payload.dart';
import 'package:halkyon_learn_flutter/src/core/content/revision_merge.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_gateway.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_payload.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_repository.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/feature/card/model/card.dart';
import 'package:halkyon_learn_flutter/src/feature/card/model/card_browser.dart';
import 'package:halkyon_learn_flutter/src/feature/card/model/card_content.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/feature/card/model/card_content.dart';
void main() {

View file

@ -1,5 +1,5 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/feature/card/model/card_content.dart';
import 'package:halkyon_learn_flutter/src/feature/card/model/card_merge.dart';
import 'package:halkyon_learn_flutter/src/feature/card/model/card_revision.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/router/route_paths.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_repository.dart';
import 'package:halkyon_learn_flutter/src/feature/card/model/card_content.dart';

View file

@ -2,9 +2,8 @@ import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_learn_flutter/src/core/content/content_blocks.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_learn_flutter/src/core/editor/rich_content_editor.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/editor/learn_content.dart';
import 'package:halkyon_learn_flutter/src/core/router/route_paths.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_payload.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_repository.dart';
@ -351,12 +350,12 @@ void main() {
await tester.tap(find.text('cat', findRichText: true));
await settle(tester);
expect(find.byType(RichContentEditor), findsOneWidget);
expect(find.byType(LearnContentEditor), findsOneWidget);
tester.view.viewInsets = const FakeViewPadding(bottom: 400);
await settle(tester);
expect(
tester.getBottomLeft(find.byType(RichContentEditor)).dy,
tester.getBottomLeft(find.byType(LearnContentEditor)).dy,
lessThanOrEqualTo(915 - 400),
);
});
@ -372,7 +371,7 @@ void main() {
expect(find.byTooltip('Bold'), findsOneWidget);
// A short field opens as low as a field gets, the bar within.
expect(
tester.getSize(find.byType(RichContentEditor)).height,
tester.getSize(find.byType(LearnContentEditor)).height,
CardFace.defaultMinEditorHeight,
);
@ -405,7 +404,7 @@ void main() {
await settle(tester);
final editor = tester.widget<AppFlowyEditor>(
find.descendant(
of: find.byType(RichContentEditor),
of: find.byType(LearnContentEditor),
matching: find.byType(AppFlowyEditor),
),
);
@ -414,7 +413,7 @@ void main() {
);
await slash.handler(editor.editorState);
await tester.pumpAndSettle();
expect(find.byType(RichContentEditor), findsOneWidget);
expect(find.byType(LearnContentEditor), findsOneWidget);
// The menu builds only the items near what it shows.
final menu = find.descendant(
@ -504,10 +503,10 @@ void main() {
expect(find.text('Correct answer'), findsOneWidget);
expect(find.text('Wrong answer'), findsOneWidget);
// The new answer is the one open, framed by its card alone.
expect(find.byType(RichContentEditor), findsOneWidget);
expect(find.byType(LearnContentEditor), findsOneWidget);
expect(
find.ancestor(
of: find.byType(RichContentEditor),
of: find.byType(LearnContentEditor),
matching: find.byWidgetPredicate(
(widget) => widget is CardFace && widget.accent != null,
),
@ -530,19 +529,19 @@ void main() {
await tester.tap(inField('cat'));
await settle(tester);
expect(find.byType(RichContentEditor), findsOneWidget);
expect(find.byType(LearnContentEditor), findsOneWidget);
await tester.tapAt(outside, kind: PointerDeviceKind.mouse);
await settle(tester);
expect(find.byType(RichContentEditor), findsNothing);
expect(find.byType(LearnContentEditor), findsNothing);
await tester.tap(inField('cat'));
await settle(tester);
await tester.dragFrom(outside, const Offset(0, -40));
await settle(tester);
expect(find.byType(RichContentEditor), findsOneWidget);
expect(find.byType(LearnContentEditor), findsOneWidget);
await tester.tapAt(tester.getCenter(find.text('Back')));
await settle(tester);
expect(find.byType(RichContentEditor), findsNothing);
expect(find.byType(LearnContentEditor), findsNothing);
});
testWidgets('a field closed after writing in it is not left lit as if '
@ -559,7 +558,7 @@ void main() {
await mouse.down(tester.getCenter(inField('cat')));
await mouse.up();
await settle(tester);
expect(find.byType(RichContentEditor), findsOneWidget);
expect(find.byType(LearnContentEditor), findsOneWidget);
// Into the question, the pointer leaving the answer on its way.
final front = tester.getCenter(inField('猫'));

View file

@ -1,5 +1,5 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:halkyon_learn_flutter/src/core/router/route_paths.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_payload.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_repository.dart';

Some files were not shown because too many files have changed in this diff Show more