Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion packages/flutter/lib/src/widgets/text_selection.dart
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,15 @@ class TextSelectionOverlay {
required TextMagnifierConfiguration magnifierConfiguration,
}) : _handlesVisible = handlesVisible,
_value = value {
// TODO(polina-c): stop duplicating code across disposables
// https://github.com/flutter/flutter/issues/137435
if (kFlutterMemoryAllocationsEnabled) {
MemoryAllocations.instance.dispatchObjectCreated(
library: 'package:flutter/widgets.dart',
className: '$TextSelectionOverlay',
object: this,
);
}
renderObject.selectionStartInViewport.addListener(_updateTextSelectionOverlayVisibilities);
renderObject.selectionEndInViewport.addListener(_updateTextSelectionOverlayVisibilities);
_updateTextSelectionOverlayVisibilities();
Expand Down Expand Up @@ -585,6 +594,11 @@ class TextSelectionOverlay {

/// {@macro flutter.widgets.SelectionOverlay.dispose}
void dispose() {
// TODO(polina-c): stop duplicating code across disposables
// https://github.com/flutter/flutter/issues/137435
if (kFlutterMemoryAllocationsEnabled) {
MemoryAllocations.instance.dispatchObjectDisposed(object: this);
}
_selectionOverlay.dispose();
renderObject.selectionStartInViewport.removeListener(_updateTextSelectionOverlayVisibilities);
renderObject.selectionEndInViewport.removeListener(_updateTextSelectionOverlayVisibilities);
Expand Down Expand Up @@ -956,7 +970,17 @@ class SelectionOverlay {
_lineHeightAtEnd = lineHeightAtEnd,
_selectionEndpoints = selectionEndpoints,
_toolbarLocation = toolbarLocation,
assert(debugCheckHasOverlay(context));
assert(debugCheckHasOverlay(context)) {
// TODO(polina-c): stop duplicating code across disposables
// https://github.com/flutter/flutter/issues/137435
if (kFlutterMemoryAllocationsEnabled) {
MemoryAllocations.instance.dispatchObjectCreated(
library: 'package:flutter/widgets.dart',
className: '$SelectionOverlay',
object: this,
);
}
}

/// {@macro flutter.widgets.SelectionOverlay.context}
final BuildContext context;
Expand Down Expand Up @@ -1506,6 +1530,11 @@ class SelectionOverlay {
/// Disposes this object and release resources.
/// {@endtemplate}
void dispose() {
// TODO(polina-c): stop duplicating code across disposables
// https://github.com/flutter/flutter/issues/137435
if (kFlutterMemoryAllocationsEnabled) {
MemoryAllocations.instance.dispatchObjectDisposed(object: this);
}
hide();
_magnifierInfo.dispose();
}
Expand Down
78 changes: 78 additions & 0 deletions packages/flutter/test/widgets/text_selection_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,19 @@ void main() {
);
}

testWidgetsWithLeakTracking('dispatches memory events', (WidgetTester tester) async {
await expectLater(
await memoryEvents(
() async {
final SelectionOverlay overlay = await pumpApp(tester);
overlay.dispose();
},
SelectionOverlay,
),
areCreateAndDispose,
);
});

testWidgetsWithLeakTracking('can show and hide handles', (WidgetTester tester) async {
final TextSelectionControlsSpy spy = TextSelectionControlsSpy();
final SelectionOverlay selectionOverlay = await pumpApp(
Expand Down Expand Up @@ -1703,6 +1716,71 @@ void main() {
expect(controller.selection.extentOffset, controller.text.length);
expect(scrollController.position.pixels, scrollController.position.maxScrollExtent);
});

group('TextSelectionOverlay', () {
Future<TextSelectionOverlay> pumpApp(WidgetTester tester) async {
final UniqueKey column = UniqueKey();
final LayerLink startHandleLayerLink = LayerLink();
final LayerLink endHandleLayerLink = LayerLink();
final LayerLink toolbarLayerLink = LayerLink();

final UniqueKey editableText = UniqueKey();
final TextEditingController controller = TextEditingController();
addTearDown(controller.dispose);
final FocusNode focusNode = FocusNode();
addTearDown(focusNode.dispose);

await tester.pumpWidget(MaterialApp(
home: Column(
key: column,
children: <Widget>[
FakeEditableText(
key: editableText,
controller: controller,
focusNode: focusNode,
),
CompositedTransformTarget(
link: startHandleLayerLink,
child: const Text('start handle'),
),
CompositedTransformTarget(
link: endHandleLayerLink,
child: const Text('end handle'),
),
CompositedTransformTarget(
link: toolbarLayerLink,
child: const Text('toolbar'),
),
],
),
));

return TextSelectionOverlay(
value: TextEditingValue.empty,
renderObject: tester.state<EditableTextState>(find.byKey(editableText)).renderEditable,
context: tester.element(find.byKey(column)),
onSelectionHandleTapped: () {},
startHandleLayerLink: startHandleLayerLink,
endHandleLayerLink: endHandleLayerLink,
selectionDelegate: FakeTextSelectionDelegate(),
toolbarLayerLink: toolbarLayerLink,
magnifierConfiguration: TextMagnifierConfiguration.disabled,
);
}

testWidgetsWithLeakTracking('dispatches memory events', (WidgetTester tester) async {
await expectLater(
await memoryEvents(
() async {
final TextSelectionOverlay overlay = await pumpApp(tester);
overlay.dispose();
},
TextSelectionOverlay,
),
areCreateAndDispose,
);
});
});
}

class FakeTextSelectionGestureDetectorBuilderDelegate implements TextSelectionGestureDetectorBuilderDelegate {
Expand Down