fix: detach shrink-wrapped editor listeners on dispose
This commit is contained in:
parent
e95e16a2ce
commit
829d4edf2e
2 changed files with 82 additions and 17 deletions
|
|
@ -24,22 +24,13 @@ class EditorScrollController {
|
|||
// if shrinkWrap is true, we will render the document with Column layout.
|
||||
// otherwise, we will render the document with ScrollablePositionedList.
|
||||
if (shrinkWrap) {
|
||||
void updateVisibleRange() {
|
||||
visibleRangeNotifier.value = (
|
||||
0,
|
||||
editorState.document.root.children.length - 1,
|
||||
);
|
||||
}
|
||||
|
||||
updateVisibleRange();
|
||||
editorState.document.root.addListener(updateVisibleRange);
|
||||
_updateVisibleRange();
|
||||
editorState.document.root.addListener(_updateVisibleRange);
|
||||
|
||||
shouldDisposeScrollController = scrollController == null;
|
||||
this.scrollController = scrollController ?? ScrollController();
|
||||
// listen to the scroll offset
|
||||
this.scrollController.addListener(
|
||||
() => offsetNotifier.value = this.scrollController.offset,
|
||||
);
|
||||
this.scrollController.addListener(_updateScrollOffset);
|
||||
} else {
|
||||
// listen to the scroll offset
|
||||
_scrollOffsetSubscription = _scrollOffsetListener.changes.listen((value) {
|
||||
|
|
@ -141,13 +132,23 @@ class EditorScrollController {
|
|||
|
||||
late final StreamSubscription<double> _scrollOffsetSubscription;
|
||||
|
||||
void _updateVisibleRange() {
|
||||
visibleRangeNotifier.value = (
|
||||
0,
|
||||
editorState.document.root.children.length - 1,
|
||||
);
|
||||
}
|
||||
|
||||
void _updateScrollOffset() {
|
||||
offsetNotifier.value = scrollController.offset;
|
||||
}
|
||||
|
||||
// dispose the subscription
|
||||
void dispose() {
|
||||
if (shouldDisposeScrollController) {
|
||||
scrollController.dispose();
|
||||
}
|
||||
|
||||
if (!shrinkWrap) {
|
||||
if (shrinkWrap) {
|
||||
editorState.document.root.removeListener(_updateVisibleRange);
|
||||
scrollController.removeListener(_updateScrollOffset);
|
||||
} else {
|
||||
_scrollOffsetSubscription.cancel();
|
||||
_itemPositionsListener.itemPositions.removeListener(_listenItemPositions);
|
||||
(_itemPositionsListener as ItemPositionsNotifier?)
|
||||
|
|
@ -155,6 +156,10 @@ class EditorScrollController {
|
|||
.dispose();
|
||||
}
|
||||
|
||||
if (shouldDisposeScrollController) {
|
||||
scrollController.dispose();
|
||||
}
|
||||
|
||||
offsetNotifier.dispose();
|
||||
visibleRangeNotifier.dispose();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets(
|
||||
'disposing a shrink-wrapped controller detaches document listeners',
|
||||
(tester) async {
|
||||
final editorState = EditorState.blank(withInitialText: false);
|
||||
addTearDown(editorState.dispose);
|
||||
final scrollController = EditorScrollController(
|
||||
editorState: editorState,
|
||||
shrinkWrap: true,
|
||||
);
|
||||
|
||||
scrollController.dispose();
|
||||
editorState.document.insert([0], [paragraphNode()]);
|
||||
|
||||
expect(tester.takeException(), isNull);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'disposing a shrink-wrapped controller detaches external scroll listeners',
|
||||
(tester) async {
|
||||
final editorState = EditorState.blank(withInitialText: false);
|
||||
final externalScrollController = _TestScrollController();
|
||||
addTearDown(editorState.dispose);
|
||||
addTearDown(externalScrollController.dispose);
|
||||
final scrollController = EditorScrollController(
|
||||
editorState: editorState,
|
||||
shrinkWrap: true,
|
||||
scrollController: externalScrollController,
|
||||
);
|
||||
|
||||
expect(externalScrollController.listenerCount, 1);
|
||||
scrollController.dispose();
|
||||
|
||||
expect(externalScrollController.listenerCount, 0);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
class _TestScrollController extends ScrollController {
|
||||
final Set<VoidCallback> _listeners = {};
|
||||
|
||||
int get listenerCount => _listeners.length;
|
||||
|
||||
@override
|
||||
void addListener(VoidCallback listener) {
|
||||
_listeners.add(listener);
|
||||
super.addListener(listener);
|
||||
}
|
||||
|
||||
@override
|
||||
void removeListener(VoidCallback listener) {
|
||||
_listeners.remove(listener);
|
||||
super.removeListener(listener);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue