fix: editor will crash if deleting all nodes (#1037)
* fix: editor will crash if deleting all nodes * chore: disable windows ci
This commit is contained in:
parent
8868c50aef
commit
1df3cb1a1f
6 changed files with 41 additions and 9 deletions
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
|
|
@ -23,7 +23,7 @@ jobs:
|
||||||
desktop:
|
desktop:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
os: [macos-latest, ubuntu-latest]
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,9 +105,7 @@ class _DesktopEditorState extends State<DesktopEditor> {
|
||||||
height: 150,
|
height: 150,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
footer: const SizedBox(
|
footer: _buildFooter(),
|
||||||
height: 100,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -216,6 +214,32 @@ class _DesktopEditorState extends State<DesktopEditor> {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildFooter() {
|
||||||
|
return SizedBox(
|
||||||
|
height: 100,
|
||||||
|
child: GestureDetector(
|
||||||
|
behavior: HitTestBehavior.opaque,
|
||||||
|
onTap: () async {
|
||||||
|
// check if the document is empty, if so, add a new paragraph block.
|
||||||
|
if (editorState.document.root.children.isEmpty) {
|
||||||
|
final transaction = editorState.transaction;
|
||||||
|
transaction.insertNode(
|
||||||
|
[0],
|
||||||
|
paragraphNode(),
|
||||||
|
);
|
||||||
|
await editorState.apply(transaction);
|
||||||
|
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
editorState.selection = Selection.collapsed(
|
||||||
|
Position(path: [0]),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
String? _buildAutoCompleteTextProvider(
|
String? _buildAutoCompleteTextProvider(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
Node node,
|
Node node,
|
||||||
|
|
|
||||||
|
|
@ -192,10 +192,11 @@ class EditorScrollController {
|
||||||
|
|
||||||
final index = offset.toInt();
|
final index = offset.toInt();
|
||||||
final (start, end) = visibleRangeNotifier.value;
|
final (start, end) = visibleRangeNotifier.value;
|
||||||
|
|
||||||
if (index < start || index > end) {
|
if (index < start || index > end) {
|
||||||
itemScrollController.jumpTo(
|
itemScrollController.jumpTo(
|
||||||
index: max(0, index),
|
index: max(0, index),
|
||||||
alignment: 0.5,
|
alignment: 0,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,11 @@ class _ScrollServiceWidgetState extends State<ScrollServiceWidget>
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (endTouchPoint == null) {
|
if (endTouchPoint == null) {
|
||||||
|
// check if the selection is valid
|
||||||
|
final node = editorState.getNodeAtPath(selection.end.path);
|
||||||
|
if (node == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
jumpTo(selection.end.path.first);
|
jumpTo(selection.end.path.first);
|
||||||
} else {
|
} else {
|
||||||
startAutoScroll(
|
startAutoScroll(
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
|
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
import 'package:appflowy_editor/src/editor/editor_component/service/selection/mobile_selection_service.dart';
|
import 'package:appflowy_editor/src/editor/editor_component/service/selection/mobile_selection_service.dart';
|
||||||
import 'package:appflowy_editor/src/editor/editor_component/service/selection/shared.dart';
|
import 'package:appflowy_editor/src/editor/editor_component/service/selection/shared.dart';
|
||||||
import 'package:appflowy_editor/src/service/selection/selection_gesture.dart';
|
import 'package:appflowy_editor/src/service/selection/selection_gesture.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class DesktopSelectionServiceWidget extends StatefulWidget {
|
class DesktopSelectionServiceWidget extends StatefulWidget {
|
||||||
|
|
@ -153,6 +152,10 @@ class _DesktopSelectionServiceWidgetState
|
||||||
context.read<EditorScrollController>(),
|
context.read<EditorScrollController>(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (sortedNodes.isEmpty) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return editorState.getNodeInOffset(
|
return editorState.getNodeInOffset(
|
||||||
sortedNodes,
|
sortedNodes,
|
||||||
offset,
|
offset,
|
||||||
|
|
|
||||||
|
|
@ -258,7 +258,6 @@ class EditorState {
|
||||||
|
|
||||||
// only used for testing
|
// only used for testing
|
||||||
bool disableSealTimer = false;
|
bool disableSealTimer = false;
|
||||||
bool disableRules = false;
|
|
||||||
|
|
||||||
@Deprecated('use editorState.selection instead')
|
@Deprecated('use editorState.selection instead')
|
||||||
Selection? _cursorSelection;
|
Selection? _cursorSelection;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue