fix: selection race condition (#1194)
* fix: guard debounced desktop selection update Avoid dereferencing a cleared selection from the delayed macOS metrics callback and add a regression test that covers the stale-timer path. * chore: clean up analyzer warnings Remove redundant default arguments in tests and apply the missing trailing comma required by the current lint rules.
This commit is contained in:
parent
37521c205f
commit
6fbe7ba442
5 changed files with 50 additions and 5 deletions
|
|
@ -81,7 +81,13 @@ class _DesktopSelectionServiceWidgetState
|
|||
Debounce.debounce(
|
||||
'didChangeMetrics - update selection ',
|
||||
const Duration(milliseconds: 100),
|
||||
() => updateSelection(currentSelection.value!),
|
||||
() {
|
||||
final selection = currentSelection.value;
|
||||
if (!mounted || selection == null) {
|
||||
return;
|
||||
}
|
||||
updateSelection(selection);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ void main() {
|
|||
|
||||
scroller.startAutoScroll(
|
||||
offset,
|
||||
edgeOffset: edgeOffset,
|
||||
direction: AxisDirection.up,
|
||||
);
|
||||
|
||||
|
|
@ -96,7 +95,6 @@ void main() {
|
|||
|
||||
scroller.startAutoScroll(
|
||||
offset,
|
||||
edgeOffset: edgeOffset,
|
||||
direction: AxisDirection.down,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
import 'dart:ui';
|
||||
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import '../../../test_helper.dart';
|
||||
|
||||
void main() {
|
||||
group('DesktopSelectionServiceWidget', () {
|
||||
testWidgets(
|
||||
'does not crash when selection is cleared before metric debounce fires',
|
||||
(tester) async {
|
||||
final editorState = EditorState(document: Document.blank());
|
||||
|
||||
addTearDown(tester.view.resetPhysicalSize);
|
||||
addTearDown(tester.view.resetDevicePixelRatio);
|
||||
|
||||
tester.view.devicePixelRatio = 1.0;
|
||||
|
||||
await tester.buildAndPump(
|
||||
AppFlowyEditor(
|
||||
editorState: editorState,
|
||||
),
|
||||
);
|
||||
|
||||
editorState.selectionService.updateSelection(
|
||||
Selection.collapsed(Position(path: [0])),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
tester.view.physicalSize = const Size(1600, 1200);
|
||||
await tester.pump();
|
||||
|
||||
editorState.selection = null;
|
||||
await tester.pump(const Duration(milliseconds: 101));
|
||||
|
||||
expect(tester.takeException(), isNull);
|
||||
expect(editorState.selectionService.currentSelection.value, isNull);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
@ -427,7 +427,6 @@ void main() async {
|
|||
transaction,
|
||||
options: const ApplyOptions(
|
||||
recordUndo: false,
|
||||
recordRedo: false,
|
||||
source: TransactionSource.none,
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ void main() async {
|
|||
|
||||
// Place cursor at [0] offset 0
|
||||
await editor.updateSelection(
|
||||
Selection.collapsed(Position(path: [0], offset: 0)),
|
||||
Selection.collapsed(Position(path: [0])),
|
||||
);
|
||||
|
||||
// Type 4 characters with pumpAndSettle between each
|
||||
|
|
|
|||
Loading…
Reference in a new issue