|
@@ -1,10 +1,12 @@
|
|
|
|
+import 'dart:collection';
|
|
|
|
+
|
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
|
import 'package:appflowy_editor/src/render/image/image_node_widget.dart';
|
|
import 'package:appflowy_editor/src/render/image/image_node_widget.dart';
|
|
|
|
+import 'package:appflowy_editor/src/render/rich_text/flowy_rich_text.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:network_image_mock/network_image_mock.dart';
|
|
import 'package:network_image_mock/network_image_mock.dart';
|
|
import '../../infra/test_editor.dart';
|
|
import '../../infra/test_editor.dart';
|
|
-import 'package:appflowy_editor/src/document/built_in_attribute_keys.dart';
|
|
|
|
|
|
|
|
void main() async {
|
|
void main() async {
|
|
setUpAll(() {
|
|
setUpAll(() {
|
|
@@ -267,6 +269,140 @@ void main() async {
|
|
BuiltInAttributeKey.h1,
|
|
BuiltInAttributeKey.h1,
|
|
);
|
|
);
|
|
});
|
|
});
|
|
|
|
+
|
|
|
|
+ testWidgets('Delete the nested bulleted list', (tester) async {
|
|
|
|
+ // * Welcome to Appflowy 😁
|
|
|
|
+ // * Welcome to Appflowy 😁
|
|
|
|
+ // * Welcome to Appflowy 😁
|
|
|
|
+ const text = 'Welcome to Appflowy 😁';
|
|
|
|
+ final node = TextNode(
|
|
|
|
+ type: 'text',
|
|
|
|
+ delta: Delta()..insert(text),
|
|
|
|
+ attributes: {
|
|
|
|
+ BuiltInAttributeKey.subtype: BuiltInAttributeKey.bulletedList,
|
|
|
|
+ },
|
|
|
|
+ );
|
|
|
|
+ node.insert(
|
|
|
|
+ node.copyWith()
|
|
|
|
+ ..insert(
|
|
|
|
+ node.copyWith(),
|
|
|
|
+ ),
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ final editor = tester.editor..insert(node);
|
|
|
|
+ await editor.startTesting();
|
|
|
|
+
|
|
|
|
+ // * Welcome to Appflowy 😁
|
|
|
|
+ // * Welcome to Appflowy 😁
|
|
|
|
+ // Welcome to Appflowy 😁
|
|
|
|
+ await editor.updateSelection(
|
|
|
|
+ Selection.single(path: [0, 0, 0], startOffset: 0),
|
|
|
|
+ );
|
|
|
|
+ await editor.pressLogicKey(LogicalKeyboardKey.backspace);
|
|
|
|
+ expect(editor.nodeAtPath([0, 0, 0])?.subtype, null);
|
|
|
|
+ await editor.updateSelection(
|
|
|
|
+ Selection.single(path: [0, 0, 0], startOffset: 0),
|
|
|
|
+ );
|
|
|
|
+ await editor.pressLogicKey(LogicalKeyboardKey.backspace);
|
|
|
|
+ expect(editor.nodeAtPath([0, 1]) != null, true);
|
|
|
|
+ await editor.updateSelection(
|
|
|
|
+ Selection.single(path: [0, 1], startOffset: 0),
|
|
|
|
+ );
|
|
|
|
+ await editor.pressLogicKey(LogicalKeyboardKey.backspace);
|
|
|
|
+ expect(editor.nodeAtPath([1]) != null, true);
|
|
|
|
+ await editor.updateSelection(
|
|
|
|
+ Selection.single(path: [1], startOffset: 0),
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ // * Welcome to Appflowy 😁
|
|
|
|
+ // * Welcome to Appflowy 😁Welcome to Appflowy 😁
|
|
|
|
+ await editor.pressLogicKey(LogicalKeyboardKey.backspace);
|
|
|
|
+ expect(
|
|
|
|
+ editor.documentSelection,
|
|
|
|
+ Selection.single(path: [0, 0], startOffset: text.length),
|
|
|
|
+ );
|
|
|
|
+ expect((editor.nodeAtPath([0, 0]) as TextNode).toRawString(), text * 2);
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ testWidgets('Delete the complicated nested bulleted list', (tester) async {
|
|
|
|
+ // * Welcome to Appflowy 😁
|
|
|
|
+ // * Welcome to Appflowy 😁
|
|
|
|
+ // * Welcome to Appflowy 😁
|
|
|
|
+ // * Welcome to Appflowy 😁
|
|
|
|
+ // * Welcome to Appflowy 😁
|
|
|
|
+ const text = 'Welcome to Appflowy 😁';
|
|
|
|
+ final node = TextNode(
|
|
|
|
+ type: 'text',
|
|
|
|
+ delta: Delta()..insert(text),
|
|
|
|
+ attributes: {
|
|
|
|
+ BuiltInAttributeKey.subtype: BuiltInAttributeKey.bulletedList,
|
|
|
|
+ },
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ node
|
|
|
|
+ ..insert(
|
|
|
|
+ node.copyWith(children: LinkedList()),
|
|
|
|
+ )
|
|
|
|
+ ..insert(
|
|
|
|
+ node.copyWith(children: LinkedList())
|
|
|
|
+ ..insert(
|
|
|
|
+ node.copyWith(children: LinkedList()),
|
|
|
|
+ )
|
|
|
|
+ ..insert(
|
|
|
|
+ node.copyWith(children: LinkedList()),
|
|
|
|
+ ),
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ final editor = tester.editor..insert(node);
|
|
|
|
+ await editor.startTesting();
|
|
|
|
+
|
|
|
|
+ await editor.updateSelection(
|
|
|
|
+ Selection.single(path: [0, 1], startOffset: 0),
|
|
|
|
+ );
|
|
|
|
+ await editor.pressLogicKey(LogicalKeyboardKey.backspace);
|
|
|
|
+ expect(
|
|
|
|
+ editor.nodeAtPath([0, 1])!.subtype != BuiltInAttributeKey.bulletedList,
|
|
|
|
+ true,
|
|
|
|
+ );
|
|
|
|
+ expect(
|
|
|
|
+ editor.nodeAtPath([0, 1, 0])!.subtype,
|
|
|
|
+ BuiltInAttributeKey.bulletedList,
|
|
|
|
+ );
|
|
|
|
+ expect(
|
|
|
|
+ editor.nodeAtPath([0, 1, 1])!.subtype,
|
|
|
|
+ BuiltInAttributeKey.bulletedList,
|
|
|
|
+ );
|
|
|
|
+ expect(find.byType(FlowyRichText), findsNWidgets(5));
|
|
|
|
+
|
|
|
|
+ // Before
|
|
|
|
+ // * Welcome to Appflowy 😁
|
|
|
|
+ // * Welcome to Appflowy 😁
|
|
|
|
+ // Welcome to Appflowy 😁
|
|
|
|
+ // * Welcome to Appflowy 😁
|
|
|
|
+ // * Welcome to Appflowy 😁
|
|
|
|
+ // After
|
|
|
|
+ // * Welcome to Appflowy 😁
|
|
|
|
+ // * Welcome to Appflowy 😁Welcome to Appflowy 😁
|
|
|
|
+ // * Welcome to Appflowy 😁
|
|
|
|
+ // * Welcome to Appflowy 😁
|
|
|
|
+ await editor.pressLogicKey(LogicalKeyboardKey.backspace);
|
|
|
|
+ expect(
|
|
|
|
+ editor.nodeAtPath([0, 0])!.subtype == BuiltInAttributeKey.bulletedList,
|
|
|
|
+ true,
|
|
|
|
+ );
|
|
|
|
+ expect(
|
|
|
|
+ (editor.nodeAtPath([0, 0]) as TextNode).toRawString() == text * 2,
|
|
|
|
+ true,
|
|
|
|
+ );
|
|
|
|
+ expect(
|
|
|
|
+ editor.nodeAtPath([0, 1])!.subtype == BuiltInAttributeKey.bulletedList,
|
|
|
|
+ true,
|
|
|
|
+ );
|
|
|
|
+ expect(
|
|
|
|
+ editor.nodeAtPath([0, 2])!.subtype == BuiltInAttributeKey.bulletedList,
|
|
|
|
+ true,
|
|
|
|
+ );
|
|
|
|
+ });
|
|
}
|
|
}
|
|
|
|
|
|
Future<void> _deleteFirstImage(WidgetTester tester, bool isBackward) async {
|
|
Future<void> _deleteFirstImage(WidgetTester tester, bool isBackward) async {
|