Unverified Commit 64d9ea60 authored by chunhtai's avatar chunhtai Committed by GitHub

Revert "Clean up ClipboardStatusNotifier (#98951)" (#99361)

This reverts commit c74a646b.
parent bf98767e
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
...@@ -49,15 +48,15 @@ class _CupertinoDesktopTextSelectionControls extends TextSelectionControls { ...@@ -49,15 +48,15 @@ class _CupertinoDesktopTextSelectionControls extends TextSelectionControls {
Offset selectionMidpoint, Offset selectionMidpoint,
List<TextSelectionPoint> endpoints, List<TextSelectionPoint> endpoints,
TextSelectionDelegate delegate, TextSelectionDelegate delegate,
ValueListenable<ClipboardStatus>? clipboardStatus, ClipboardStatusNotifier clipboardStatus,
Offset? lastSecondaryTapDownPosition, Offset? lastSecondaryTapDownPosition,
) { ) {
return _CupertinoDesktopTextSelectionControlsToolbar( return _CupertinoDesktopTextSelectionControlsToolbar(
clipboardStatus: clipboardStatus, clipboardStatus: clipboardStatus,
endpoints: endpoints, endpoints: endpoints,
globalEditableRegion: globalEditableRegion, globalEditableRegion: globalEditableRegion,
handleCut: canCut(delegate) ? () => handleCut(delegate) : null, handleCut: canCut(delegate) ? () => handleCut(delegate, clipboardStatus) : null,
handleCopy: canCopy(delegate) ? () => handleCopy(delegate) : null, handleCopy: canCopy(delegate) ? () => handleCopy(delegate, clipboardStatus) : null,
handlePaste: canPaste(delegate) ? () => handlePaste(delegate) : null, handlePaste: canPaste(delegate) ? () => handlePaste(delegate) : null,
handleSelectAll: canSelectAll(delegate) ? () => handleSelectAll(delegate) : null, handleSelectAll: canSelectAll(delegate) ? () => handleSelectAll(delegate) : null,
selectionMidpoint: selectionMidpoint, selectionMidpoint: selectionMidpoint,
...@@ -99,7 +98,7 @@ class _CupertinoDesktopTextSelectionControlsToolbar extends StatefulWidget { ...@@ -99,7 +98,7 @@ class _CupertinoDesktopTextSelectionControlsToolbar extends StatefulWidget {
required this.lastSecondaryTapDownPosition, required this.lastSecondaryTapDownPosition,
}) : super(key: key); }) : super(key: key);
final ValueListenable<ClipboardStatus>? clipboardStatus; final ClipboardStatusNotifier? clipboardStatus;
final List<TextSelectionPoint> endpoints; final List<TextSelectionPoint> endpoints;
final Rect globalEditableRegion; final Rect globalEditableRegion;
final VoidCallback? handleCopy; final VoidCallback? handleCopy;
...@@ -115,6 +114,8 @@ class _CupertinoDesktopTextSelectionControlsToolbar extends StatefulWidget { ...@@ -115,6 +114,8 @@ class _CupertinoDesktopTextSelectionControlsToolbar extends StatefulWidget {
} }
class _CupertinoDesktopTextSelectionControlsToolbarState extends State<_CupertinoDesktopTextSelectionControlsToolbar> { class _CupertinoDesktopTextSelectionControlsToolbarState extends State<_CupertinoDesktopTextSelectionControlsToolbar> {
ClipboardStatusNotifier? _clipboardStatus;
void _onChangedClipboardStatus() { void _onChangedClipboardStatus() {
setState(() { setState(() {
// Inform the widget that the value of clipboardStatus has changed. // Inform the widget that the value of clipboardStatus has changed.
...@@ -124,28 +125,46 @@ class _CupertinoDesktopTextSelectionControlsToolbarState extends State<_Cupertin ...@@ -124,28 +125,46 @@ class _CupertinoDesktopTextSelectionControlsToolbarState extends State<_Cupertin
@override @override
void initState() { void initState() {
super.initState(); super.initState();
widget.clipboardStatus?.addListener(_onChangedClipboardStatus); if (widget.handlePaste != null) {
_clipboardStatus = widget.clipboardStatus ?? ClipboardStatusNotifier();
_clipboardStatus!.addListener(_onChangedClipboardStatus);
_clipboardStatus!.update();
}
} }
@override @override
void didUpdateWidget(_CupertinoDesktopTextSelectionControlsToolbar oldWidget) { void didUpdateWidget(_CupertinoDesktopTextSelectionControlsToolbar oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (oldWidget.clipboardStatus != widget.clipboardStatus) { if (oldWidget.clipboardStatus != widget.clipboardStatus) {
oldWidget.clipboardStatus?.removeListener(_onChangedClipboardStatus); if (_clipboardStatus != null) {
widget.clipboardStatus?.addListener(_onChangedClipboardStatus); _clipboardStatus!.removeListener(_onChangedClipboardStatus);
_clipboardStatus!.dispose();
}
_clipboardStatus = widget.clipboardStatus ?? ClipboardStatusNotifier();
_clipboardStatus!.addListener(_onChangedClipboardStatus);
if (widget.handlePaste != null) {
_clipboardStatus!.update();
}
} }
} }
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();
widget.clipboardStatus?.removeListener(_onChangedClipboardStatus); // When used in an Overlay, this can be disposed after its creator has
// already disposed _clipboardStatus.
if (_clipboardStatus != null && !_clipboardStatus!.disposed) {
_clipboardStatus!.removeListener(_onChangedClipboardStatus);
if (widget.clipboardStatus == null) {
_clipboardStatus!.dispose();
}
}
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// Don't render the menu until the state of the clipboard is known. // Don't render the menu until the state of the clipboard is known.
if (widget.handlePaste != null && widget.clipboardStatus?.value == ClipboardStatus.unknown) { if (widget.handlePaste != null && _clipboardStatus!.value == ClipboardStatus.unknown) {
return const SizedBox(width: 0.0, height: 0.0); return const SizedBox(width: 0.0, height: 0.0);
} }
...@@ -187,7 +206,7 @@ class _CupertinoDesktopTextSelectionControlsToolbarState extends State<_Cupertin ...@@ -187,7 +206,7 @@ class _CupertinoDesktopTextSelectionControlsToolbarState extends State<_Cupertin
addToolbarButton(localizations.copyButtonLabel, widget.handleCopy!); addToolbarButton(localizations.copyButtonLabel, widget.handleCopy!);
} }
if (widget.handlePaste != null if (widget.handlePaste != null
&& widget.clipboardStatus?.value == ClipboardStatus.pasteable) { && _clipboardStatus!.value == ClipboardStatus.pasteable) {
addToolbarButton(localizations.pasteButtonLabel, widget.handlePaste!); addToolbarButton(localizations.pasteButtonLabel, widget.handlePaste!);
} }
if (widget.handleSelectAll != null) { if (widget.handleSelectAll != null) {
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
import 'dart:math' as math; import 'dart:math' as math;
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
...@@ -38,7 +37,7 @@ class _CupertinoTextSelectionControlsToolbar extends StatefulWidget { ...@@ -38,7 +37,7 @@ class _CupertinoTextSelectionControlsToolbar extends StatefulWidget {
required this.textLineHeight, required this.textLineHeight,
}) : super(key: key); }) : super(key: key);
final ValueListenable<ClipboardStatus>? clipboardStatus; final ClipboardStatusNotifier? clipboardStatus;
final List<TextSelectionPoint> endpoints; final List<TextSelectionPoint> endpoints;
final Rect globalEditableRegion; final Rect globalEditableRegion;
final VoidCallback? handleCopy; final VoidCallback? handleCopy;
...@@ -53,6 +52,8 @@ class _CupertinoTextSelectionControlsToolbar extends StatefulWidget { ...@@ -53,6 +52,8 @@ class _CupertinoTextSelectionControlsToolbar extends StatefulWidget {
} }
class _CupertinoTextSelectionControlsToolbarState extends State<_CupertinoTextSelectionControlsToolbar> { class _CupertinoTextSelectionControlsToolbarState extends State<_CupertinoTextSelectionControlsToolbar> {
ClipboardStatusNotifier? _clipboardStatus;
void _onChangedClipboardStatus() { void _onChangedClipboardStatus() {
setState(() { setState(() {
// Inform the widget that the value of clipboardStatus has changed. // Inform the widget that the value of clipboardStatus has changed.
...@@ -62,28 +63,47 @@ class _CupertinoTextSelectionControlsToolbarState extends State<_CupertinoTextSe ...@@ -62,28 +63,47 @@ class _CupertinoTextSelectionControlsToolbarState extends State<_CupertinoTextSe
@override @override
void initState() { void initState() {
super.initState(); super.initState();
widget.clipboardStatus?.addListener(_onChangedClipboardStatus); if (widget.handlePaste != null) {
_clipboardStatus = widget.clipboardStatus ?? ClipboardStatusNotifier();
_clipboardStatus!.addListener(_onChangedClipboardStatus);
_clipboardStatus!.update();
}
} }
@override @override
void didUpdateWidget(_CupertinoTextSelectionControlsToolbar oldWidget) { void didUpdateWidget(_CupertinoTextSelectionControlsToolbar oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (oldWidget.clipboardStatus != widget.clipboardStatus) { if (oldWidget.clipboardStatus != widget.clipboardStatus) {
oldWidget.clipboardStatus?.removeListener(_onChangedClipboardStatus); if (_clipboardStatus != null) {
widget.clipboardStatus?.addListener(_onChangedClipboardStatus); _clipboardStatus!.removeListener(_onChangedClipboardStatus);
_clipboardStatus!.dispose();
}
_clipboardStatus = widget.clipboardStatus ?? ClipboardStatusNotifier();
_clipboardStatus!.addListener(_onChangedClipboardStatus);
if (widget.handlePaste != null) {
_clipboardStatus!.update();
}
} }
} }
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();
widget.clipboardStatus?.removeListener(_onChangedClipboardStatus); // When used in an Overlay, this can be disposed after its creator has
// already disposed _clipboardStatus.
if (_clipboardStatus != null && !_clipboardStatus!.disposed) {
_clipboardStatus!.removeListener(_onChangedClipboardStatus);
if (widget.clipboardStatus == null) {
_clipboardStatus!.dispose();
}
}
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// Don't render the menu until the state of the clipboard is known. // Don't render the menu until the state of the clipboard is known.
if (widget.handlePaste != null && widget.clipboardStatus?.value == ClipboardStatus.unknown) { if (widget.handlePaste != null
&& _clipboardStatus!.value == ClipboardStatus.unknown) {
return const SizedBox(width: 0.0, height: 0.0); return const SizedBox(width: 0.0, height: 0.0);
} }
...@@ -137,7 +157,7 @@ class _CupertinoTextSelectionControlsToolbarState extends State<_CupertinoTextSe ...@@ -137,7 +157,7 @@ class _CupertinoTextSelectionControlsToolbarState extends State<_CupertinoTextSe
addToolbarButton(localizations.copyButtonLabel, widget.handleCopy!); addToolbarButton(localizations.copyButtonLabel, widget.handleCopy!);
} }
if (widget.handlePaste != null if (widget.handlePaste != null
&& widget.clipboardStatus?.value == ClipboardStatus.pasteable) { && _clipboardStatus!.value == ClipboardStatus.pasteable) {
addToolbarButton(localizations.pasteButtonLabel, widget.handlePaste!); addToolbarButton(localizations.pasteButtonLabel, widget.handlePaste!);
} }
if (widget.handleSelectAll != null) { if (widget.handleSelectAll != null) {
...@@ -209,15 +229,15 @@ class CupertinoTextSelectionControls extends TextSelectionControls { ...@@ -209,15 +229,15 @@ class CupertinoTextSelectionControls extends TextSelectionControls {
Offset selectionMidpoint, Offset selectionMidpoint,
List<TextSelectionPoint> endpoints, List<TextSelectionPoint> endpoints,
TextSelectionDelegate delegate, TextSelectionDelegate delegate,
ValueListenable<ClipboardStatus>? clipboardStatus, ClipboardStatusNotifier clipboardStatus,
Offset? lastSecondaryTapDownPosition, Offset? lastSecondaryTapDownPosition,
) { ) {
return _CupertinoTextSelectionControlsToolbar( return _CupertinoTextSelectionControlsToolbar(
clipboardStatus: clipboardStatus, clipboardStatus: clipboardStatus,
endpoints: endpoints, endpoints: endpoints,
globalEditableRegion: globalEditableRegion, globalEditableRegion: globalEditableRegion,
handleCut: canCut(delegate) ? () => handleCut(delegate) : null, handleCut: canCut(delegate) ? () => handleCut(delegate, clipboardStatus) : null,
handleCopy: canCopy(delegate) ? () => handleCopy(delegate) : null, handleCopy: canCopy(delegate) ? () => handleCopy(delegate, clipboardStatus) : null,
handlePaste: canPaste(delegate) ? () => handlePaste(delegate) : null, handlePaste: canPaste(delegate) ? () => handlePaste(delegate) : null,
handleSelectAll: canSelectAll(delegate) ? () => handleSelectAll(delegate) : null, handleSelectAll: canSelectAll(delegate) ? () => handleSelectAll(delegate) : null,
selectionMidpoint: selectionMidpoint, selectionMidpoint: selectionMidpoint,
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
...@@ -35,15 +34,15 @@ class _DesktopTextSelectionControls extends TextSelectionControls { ...@@ -35,15 +34,15 @@ class _DesktopTextSelectionControls extends TextSelectionControls {
Offset selectionMidpoint, Offset selectionMidpoint,
List<TextSelectionPoint> endpoints, List<TextSelectionPoint> endpoints,
TextSelectionDelegate delegate, TextSelectionDelegate delegate,
ValueListenable<ClipboardStatus>? clipboardStatus, ClipboardStatusNotifier clipboardStatus,
Offset? lastSecondaryTapDownPosition, Offset? lastSecondaryTapDownPosition,
) { ) {
return _DesktopTextSelectionControlsToolbar( return _DesktopTextSelectionControlsToolbar(
clipboardStatus: clipboardStatus, clipboardStatus: clipboardStatus,
endpoints: endpoints, endpoints: endpoints,
globalEditableRegion: globalEditableRegion, globalEditableRegion: globalEditableRegion,
handleCut: canCut(delegate) ? () => handleCut(delegate) : null, handleCut: canCut(delegate) ? () => handleCut(delegate, clipboardStatus) : null,
handleCopy: canCopy(delegate) ? () => handleCopy(delegate) : null, handleCopy: canCopy(delegate) ? () => handleCopy(delegate, clipboardStatus) : null,
handlePaste: canPaste(delegate) ? () => handlePaste(delegate) : null, handlePaste: canPaste(delegate) ? () => handlePaste(delegate) : null,
handleSelectAll: canSelectAll(delegate) ? () => handleSelectAll(delegate) : null, handleSelectAll: canSelectAll(delegate) ? () => handleSelectAll(delegate) : null,
selectionMidpoint: selectionMidpoint, selectionMidpoint: selectionMidpoint,
...@@ -95,7 +94,7 @@ class _DesktopTextSelectionControlsToolbar extends StatefulWidget { ...@@ -95,7 +94,7 @@ class _DesktopTextSelectionControlsToolbar extends StatefulWidget {
required this.lastSecondaryTapDownPosition, required this.lastSecondaryTapDownPosition,
}) : super(key: key); }) : super(key: key);
final ValueListenable<ClipboardStatus>? clipboardStatus; final ClipboardStatusNotifier? clipboardStatus;
final List<TextSelectionPoint> endpoints; final List<TextSelectionPoint> endpoints;
final Rect globalEditableRegion; final Rect globalEditableRegion;
final VoidCallback? handleCopy; final VoidCallback? handleCopy;
...@@ -111,6 +110,8 @@ class _DesktopTextSelectionControlsToolbar extends StatefulWidget { ...@@ -111,6 +110,8 @@ class _DesktopTextSelectionControlsToolbar extends StatefulWidget {
} }
class _DesktopTextSelectionControlsToolbarState extends State<_DesktopTextSelectionControlsToolbar> { class _DesktopTextSelectionControlsToolbarState extends State<_DesktopTextSelectionControlsToolbar> {
ClipboardStatusNotifier? _clipboardStatus;
void _onChangedClipboardStatus() { void _onChangedClipboardStatus() {
setState(() { setState(() {
// Inform the widget that the value of clipboardStatus has changed. // Inform the widget that the value of clipboardStatus has changed.
...@@ -120,28 +121,46 @@ class _DesktopTextSelectionControlsToolbarState extends State<_DesktopTextSelect ...@@ -120,28 +121,46 @@ class _DesktopTextSelectionControlsToolbarState extends State<_DesktopTextSelect
@override @override
void initState() { void initState() {
super.initState(); super.initState();
widget.clipboardStatus?.addListener(_onChangedClipboardStatus); if (widget.handlePaste != null) {
_clipboardStatus = widget.clipboardStatus ?? ClipboardStatusNotifier();
_clipboardStatus!.addListener(_onChangedClipboardStatus);
_clipboardStatus!.update();
}
} }
@override @override
void didUpdateWidget(_DesktopTextSelectionControlsToolbar oldWidget) { void didUpdateWidget(_DesktopTextSelectionControlsToolbar oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (oldWidget.clipboardStatus != widget.clipboardStatus) { if (oldWidget.clipboardStatus != widget.clipboardStatus) {
oldWidget.clipboardStatus?.removeListener(_onChangedClipboardStatus); if (_clipboardStatus != null) {
widget.clipboardStatus?.addListener(_onChangedClipboardStatus); _clipboardStatus!.removeListener(_onChangedClipboardStatus);
_clipboardStatus!.dispose();
}
_clipboardStatus = widget.clipboardStatus ?? ClipboardStatusNotifier();
_clipboardStatus!.addListener(_onChangedClipboardStatus);
if (widget.handlePaste != null) {
_clipboardStatus!.update();
}
} }
} }
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();
widget.clipboardStatus?.removeListener(_onChangedClipboardStatus); // When used in an Overlay, this can be disposed after its creator has
// already disposed _clipboardStatus.
if (_clipboardStatus != null && !_clipboardStatus!.disposed) {
_clipboardStatus!.removeListener(_onChangedClipboardStatus);
if (widget.clipboardStatus == null) {
_clipboardStatus!.dispose();
}
}
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// Don't render the menu until the state of the clipboard is known. // Don't render the menu until the state of the clipboard is known.
if (widget.handlePaste != null && widget.clipboardStatus?.value == ClipboardStatus.unknown) { if (widget.handlePaste != null && _clipboardStatus!.value == ClipboardStatus.unknown) {
return const SizedBox(width: 0.0, height: 0.0); return const SizedBox(width: 0.0, height: 0.0);
} }
...@@ -178,7 +197,7 @@ class _DesktopTextSelectionControlsToolbarState extends State<_DesktopTextSelect ...@@ -178,7 +197,7 @@ class _DesktopTextSelectionControlsToolbarState extends State<_DesktopTextSelect
addToolbarButton(localizations.copyButtonLabel, widget.handleCopy!); addToolbarButton(localizations.copyButtonLabel, widget.handleCopy!);
} }
if (widget.handlePaste != null if (widget.handlePaste != null
&& widget.clipboardStatus?.value == ClipboardStatus.pasteable) { && _clipboardStatus!.value == ClipboardStatus.pasteable) {
addToolbarButton(localizations.pasteButtonLabel, widget.handlePaste!); addToolbarButton(localizations.pasteButtonLabel, widget.handlePaste!);
} }
if (widget.handleSelectAll != null) { if (widget.handleSelectAll != null) {
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
import 'dart:math' as math; import 'dart:math' as math;
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
...@@ -36,7 +35,7 @@ class MaterialTextSelectionControls extends TextSelectionControls { ...@@ -36,7 +35,7 @@ class MaterialTextSelectionControls extends TextSelectionControls {
Offset selectionMidpoint, Offset selectionMidpoint,
List<TextSelectionPoint> endpoints, List<TextSelectionPoint> endpoints,
TextSelectionDelegate delegate, TextSelectionDelegate delegate,
ValueListenable<ClipboardStatus>? clipboardStatus, ClipboardStatusNotifier clipboardStatus,
Offset? lastSecondaryTapDownPosition, Offset? lastSecondaryTapDownPosition,
) { ) {
return _TextSelectionControlsToolbar( return _TextSelectionControlsToolbar(
...@@ -46,8 +45,8 @@ class MaterialTextSelectionControls extends TextSelectionControls { ...@@ -46,8 +45,8 @@ class MaterialTextSelectionControls extends TextSelectionControls {
endpoints: endpoints, endpoints: endpoints,
delegate: delegate, delegate: delegate,
clipboardStatus: clipboardStatus, clipboardStatus: clipboardStatus,
handleCut: canCut(delegate) ? () => handleCut(delegate) : null, handleCut: canCut(delegate) ? () => handleCut(delegate, clipboardStatus) : null,
handleCopy: canCopy(delegate) ? () => handleCopy(delegate) : null, handleCopy: canCopy(delegate) ? () => handleCopy(delegate, clipboardStatus) : null,
handlePaste: canPaste(delegate) ? () => handlePaste(delegate) : null, handlePaste: canPaste(delegate) ? () => handlePaste(delegate) : null,
handleSelectAll: canSelectAll(delegate) ? () => handleSelectAll(delegate) : null, handleSelectAll: canSelectAll(delegate) ? () => handleSelectAll(delegate) : null,
); );
...@@ -144,7 +143,7 @@ class _TextSelectionControlsToolbar extends StatefulWidget { ...@@ -144,7 +143,7 @@ class _TextSelectionControlsToolbar extends StatefulWidget {
required this.textLineHeight, required this.textLineHeight,
}) : super(key: key); }) : super(key: key);
final ValueListenable<ClipboardStatus>? clipboardStatus; final ClipboardStatusNotifier clipboardStatus;
final TextSelectionDelegate delegate; final TextSelectionDelegate delegate;
final List<TextSelectionPoint> endpoints; final List<TextSelectionPoint> endpoints;
final Rect globalEditableRegion; final Rect globalEditableRegion;
...@@ -169,22 +168,28 @@ class _TextSelectionControlsToolbarState extends State<_TextSelectionControlsToo ...@@ -169,22 +168,28 @@ class _TextSelectionControlsToolbarState extends State<_TextSelectionControlsToo
@override @override
void initState() { void initState() {
super.initState(); super.initState();
widget.clipboardStatus?.addListener(_onChangedClipboardStatus); widget.clipboardStatus.addListener(_onChangedClipboardStatus);
widget.clipboardStatus.update();
} }
@override @override
void didUpdateWidget(_TextSelectionControlsToolbar oldWidget) { void didUpdateWidget(_TextSelectionControlsToolbar oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (widget.clipboardStatus != oldWidget.clipboardStatus) { if (widget.clipboardStatus != oldWidget.clipboardStatus) {
widget.clipboardStatus?.addListener(_onChangedClipboardStatus); widget.clipboardStatus.addListener(_onChangedClipboardStatus);
oldWidget.clipboardStatus?.removeListener(_onChangedClipboardStatus); oldWidget.clipboardStatus.removeListener(_onChangedClipboardStatus);
} }
widget.clipboardStatus.update();
} }
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();
widget.clipboardStatus?.removeListener(_onChangedClipboardStatus); // When used in an Overlay, it can happen that this is disposed after its
// creator has already disposed _clipboardStatus.
if (!widget.clipboardStatus.disposed) {
widget.clipboardStatus.removeListener(_onChangedClipboardStatus);
}
} }
@override @override
...@@ -197,7 +202,7 @@ class _TextSelectionControlsToolbarState extends State<_TextSelectionControlsToo ...@@ -197,7 +202,7 @@ class _TextSelectionControlsToolbarState extends State<_TextSelectionControlsToo
// If the paste button is desired, don't render anything until the state of // If the paste button is desired, don't render anything until the state of
// the clipboard is known, since it's used to determine if paste is shown. // the clipboard is known, since it's used to determine if paste is shown.
if (widget.handlePaste != null if (widget.handlePaste != null
&& widget.clipboardStatus?.value == ClipboardStatus.unknown) { && widget.clipboardStatus.value == ClipboardStatus.unknown) {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
...@@ -233,7 +238,7 @@ class _TextSelectionControlsToolbarState extends State<_TextSelectionControlsToo ...@@ -233,7 +238,7 @@ class _TextSelectionControlsToolbarState extends State<_TextSelectionControlsToo
onPressed: widget.handleCopy!, onPressed: widget.handleCopy!,
), ),
if (widget.handlePaste != null if (widget.handlePaste != null
&& widget.clipboardStatus?.value == ClipboardStatus.pasteable) && widget.clipboardStatus.value == ClipboardStatus.pasteable)
_TextSelectionToolbarItemData( _TextSelectionToolbarItemData(
label: localizations.pasteButtonLabel, label: localizations.pasteButtonLabel,
onPressed: widget.handlePaste!, onPressed: widget.handlePaste!,
......
...@@ -1671,7 +1671,6 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -1671,7 +1671,6 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
break; break;
} }
} }
_clipboardStatus?.update();
} }
/// Cut current selection to [Clipboard]. /// Cut current selection to [Clipboard].
...@@ -1695,7 +1694,6 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -1695,7 +1694,6 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
}); });
hideToolbar(); hideToolbar();
} }
_clipboardStatus?.update();
} }
/// Paste text from [Clipboard]. /// Paste text from [Clipboard].
...@@ -2921,7 +2919,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -2921,7 +2919,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
if (_selectionOverlay == null || _selectionOverlay!.toolbarIsVisible) { if (_selectionOverlay == null || _selectionOverlay!.toolbarIsVisible) {
return false; return false;
} }
_clipboardStatus?.update();
_selectionOverlay!.showToolbar(); _selectionOverlay!.showToolbar();
return true; return true;
} }
...@@ -3028,7 +3026,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -3028,7 +3026,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
&& copyEnabled && copyEnabled
&& _hasFocus && _hasFocus
&& (controls?.canCopy(this) ?? false) && (controls?.canCopy(this) ?? false)
? () => controls!.handleCopy(this) ? () => controls!.handleCopy(this, _clipboardStatus)
: null; : null;
} }
...@@ -3037,7 +3035,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -3037,7 +3035,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
&& cutEnabled && cutEnabled
&& _hasFocus && _hasFocus
&& (controls?.canCut(this) ?? false) && (controls?.canCut(this) ?? false)
? () => controls!.handleCut(this) ? () => controls!.handleCut(this, _clipboardStatus)
: null; : null;
} }
......
...@@ -142,7 +142,7 @@ abstract class TextSelectionControls { ...@@ -142,7 +142,7 @@ abstract class TextSelectionControls {
Offset position, Offset position,
List<TextSelectionPoint> endpoints, List<TextSelectionPoint> endpoints,
TextSelectionDelegate delegate, TextSelectionDelegate delegate,
ValueListenable<ClipboardStatus>? clipboardStatus, ClipboardStatusNotifier clipboardStatus,
Offset? lastSecondaryTapDownPosition, Offset? lastSecondaryTapDownPosition,
); );
...@@ -199,16 +199,18 @@ abstract class TextSelectionControls { ...@@ -199,16 +199,18 @@ abstract class TextSelectionControls {
/// ///
/// This is called by subclasses when their cut affordance is activated by /// This is called by subclasses when their cut affordance is activated by
/// the user. /// the user.
void handleCut(TextSelectionDelegate delegate) { void handleCut(TextSelectionDelegate delegate, ClipboardStatusNotifier? clipboardStatus) {
delegate.cutSelection(SelectionChangedCause.toolbar); delegate.cutSelection(SelectionChangedCause.toolbar);
clipboardStatus?.update();
} }
/// Call [TextSelectionDelegate.copySelection] to copy current selection. /// Call [TextSelectionDelegate.copySelection] to copy current selection.
/// ///
/// This is called by subclasses when their copy affordance is activated by /// This is called by subclasses when their copy affordance is activated by
/// the user. /// the user.
void handleCopy(TextSelectionDelegate delegate) { void handleCopy(TextSelectionDelegate delegate, ClipboardStatusNotifier? clipboardStatus) {
delegate.copySelection(SelectionChangedCause.toolbar); delegate.copySelection(SelectionChangedCause.toolbar);
clipboardStatus?.update();
} }
/// Call [TextSelectionDelegate.pasteText] to paste text. /// Call [TextSelectionDelegate.pasteText] to paste text.
...@@ -1078,7 +1080,7 @@ class _SelectionToolbarOverlayState extends State<_SelectionToolbarOverlay> with ...@@ -1078,7 +1080,7 @@ class _SelectionToolbarOverlayState extends State<_SelectionToolbarOverlay> with
widget.midpoint, widget.midpoint,
widget.selectionEndpoints, widget.selectionEndpoints,
widget.selectionDelegate!, widget.selectionDelegate!,
widget.clipboardStatus, widget.clipboardStatus!,
widget.toolbarLocation, widget.toolbarLocation,
); );
}, },
...@@ -2129,6 +2131,8 @@ class ClipboardStatusNotifier extends ValueNotifier<ClipboardStatus> with Widget ...@@ -2129,6 +2131,8 @@ class ClipboardStatusNotifier extends ValueNotifier<ClipboardStatus> with Widget
}) : super(value); }) : super(value);
bool _disposed = false; bool _disposed = false;
/// True if this instance has been disposed.
bool get disposed => _disposed;
/// Check the [Clipboard] and update [value] if needed. /// Check the [Clipboard] and update [value] if needed.
Future<void> update() async { Future<void> update() async {
...@@ -2179,7 +2183,7 @@ class ClipboardStatusNotifier extends ValueNotifier<ClipboardStatus> with Widget ...@@ -2179,7 +2183,7 @@ class ClipboardStatusNotifier extends ValueNotifier<ClipboardStatus> with Widget
@override @override
void removeListener(VoidCallback listener) { void removeListener(VoidCallback listener) {
super.removeListener(listener); super.removeListener(listener);
if (!_disposed && !hasListeners) { if (!hasListeners) {
WidgetsBinding.instance.removeObserver(this); WidgetsBinding.instance.removeObserver(this);
} }
} }
...@@ -2199,9 +2203,9 @@ class ClipboardStatusNotifier extends ValueNotifier<ClipboardStatus> with Widget ...@@ -2199,9 +2203,9 @@ class ClipboardStatusNotifier extends ValueNotifier<ClipboardStatus> with Widget
@override @override
void dispose() { void dispose() {
super.dispose();
WidgetsBinding.instance.removeObserver(this); WidgetsBinding.instance.removeObserver(this);
_disposed = true; _disposed = true;
super.dispose();
} }
} }
......
...@@ -43,7 +43,7 @@ class MockTextSelectionControls extends TextSelectionControls { ...@@ -43,7 +43,7 @@ class MockTextSelectionControls extends TextSelectionControls {
Offset position, Offset position,
List<TextSelectionPoint> endpoints, List<TextSelectionPoint> endpoints,
TextSelectionDelegate delegate, TextSelectionDelegate delegate,
ValueListenable<ClipboardStatus>? clipboardStatus, ClipboardStatusNotifier clipboardStatus,
Offset? lastSecondaryTapDownPosition, Offset? lastSecondaryTapDownPosition,
) { ) {
throw UnimplementedError(); throw UnimplementedError();
......
...@@ -24,7 +24,7 @@ class _CustomCupertinoTextSelectionControls extends CupertinoTextSelectionContro ...@@ -24,7 +24,7 @@ class _CustomCupertinoTextSelectionControls extends CupertinoTextSelectionContro
Offset selectionMidpoint, Offset selectionMidpoint,
List<TextSelectionPoint> endpoints, List<TextSelectionPoint> endpoints,
TextSelectionDelegate delegate, TextSelectionDelegate delegate,
ValueListenable<ClipboardStatus>? clipboardStatus, ClipboardStatusNotifier clipboardStatus,
Offset? lastSecondaryTapDownPosition, Offset? lastSecondaryTapDownPosition,
) { ) {
final MediaQueryData mediaQuery = MediaQuery.of(context); final MediaQueryData mediaQuery = MediaQuery.of(context);
......
...@@ -22,7 +22,7 @@ class _CustomMaterialTextSelectionControls extends MaterialTextSelectionControls ...@@ -22,7 +22,7 @@ class _CustomMaterialTextSelectionControls extends MaterialTextSelectionControls
Offset selectionMidpoint, Offset selectionMidpoint,
List<TextSelectionPoint> endpoints, List<TextSelectionPoint> endpoints,
TextSelectionDelegate delegate, TextSelectionDelegate delegate,
ValueListenable<ClipboardStatus>? clipboardStatus, ClipboardStatusNotifier clipboardStatus,
Offset? lastSecondaryTapDownPosition, Offset? lastSecondaryTapDownPosition,
) { ) {
final TextSelectionPoint startTextSelectionPoint = endpoints[0]; final TextSelectionPoint startTextSelectionPoint = endpoints[0];
......
...@@ -11747,7 +11747,7 @@ class MockTextFormatter extends TextInputFormatter { ...@@ -11747,7 +11747,7 @@ class MockTextFormatter extends TextInputFormatter {
class MockTextSelectionControls extends Fake implements TextSelectionControls { class MockTextSelectionControls extends Fake implements TextSelectionControls {
@override @override
Widget buildToolbar(BuildContext context, Rect globalEditableRegion, double textLineHeight, Offset position, List<TextSelectionPoint> endpoints, TextSelectionDelegate delegate, ValueListenable<ClipboardStatus>? clipboardStatus, Offset? lastSecondaryTapDownPosition) { Widget buildToolbar(BuildContext context, Rect globalEditableRegion, double textLineHeight, Offset position, List<TextSelectionPoint> endpoints, TextSelectionDelegate delegate, ClipboardStatusNotifier clipboardStatus, Offset? lastSecondaryTapDownPosition) {
return Container(); return Container();
} }
...@@ -11775,7 +11775,7 @@ class MockTextSelectionControls extends Fake implements TextSelectionControls { ...@@ -11775,7 +11775,7 @@ class MockTextSelectionControls extends Fake implements TextSelectionControls {
int copyCount = 0; int copyCount = 0;
@override @override
void handleCopy(TextSelectionDelegate delegate) { void handleCopy(TextSelectionDelegate delegate, ClipboardStatusNotifier? clipboardStatus) {
copyCount += 1; copyCount += 1;
} }
...@@ -11785,7 +11785,7 @@ class MockTextSelectionControls extends Fake implements TextSelectionControls { ...@@ -11785,7 +11785,7 @@ class MockTextSelectionControls extends Fake implements TextSelectionControls {
} }
@override @override
void handleCut(TextSelectionDelegate delegate) { void handleCut(TextSelectionDelegate delegate, ClipboardStatusNotifier? clipboardStatus) {
cutCount += 1; cutCount += 1;
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/foundation.dart' show defaultTargetPlatform, ValueListenable; import 'package:flutter/foundation.dart' show defaultTargetPlatform;
import 'package:flutter/gestures.dart' show PointerDeviceKind, kSecondaryButton; import 'package:flutter/gestures.dart' show PointerDeviceKind, kSecondaryButton;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
...@@ -1034,6 +1034,28 @@ void main() { ...@@ -1034,6 +1034,28 @@ void main() {
}); });
}); });
}); });
group('TextSelectionControls', () {
test('ClipboardStatusNotifier is updated on handleCut', () async {
final FakeClipboardStatusNotifier clipboardStatus = FakeClipboardStatusNotifier();
final FakeTextSelectionDelegate delegate = FakeTextSelectionDelegate();
final CustomTextSelectionControls textSelectionControls = CustomTextSelectionControls();
expect(clipboardStatus.updateCalled, false);
textSelectionControls.handleCut(delegate, clipboardStatus);
expect(clipboardStatus.updateCalled, true);
});
test('ClipboardStatusNotifier is updated on handleCopy', () async {
final FakeClipboardStatusNotifier clipboardStatus = FakeClipboardStatusNotifier();
final FakeTextSelectionDelegate delegate = FakeTextSelectionDelegate();
final CustomTextSelectionControls textSelectionControls = CustomTextSelectionControls();
expect(clipboardStatus.updateCalled, false);
textSelectionControls.handleCopy(delegate, clipboardStatus);
expect(clipboardStatus.updateCalled, true);
});
});
} }
class FakeTextSelectionGestureDetectorBuilderDelegate implements TextSelectionGestureDetectorBuilderDelegate { class FakeTextSelectionGestureDetectorBuilderDelegate implements TextSelectionGestureDetectorBuilderDelegate {
...@@ -1162,7 +1184,7 @@ class CustomTextSelectionControls extends TextSelectionControls { ...@@ -1162,7 +1184,7 @@ class CustomTextSelectionControls extends TextSelectionControls {
Offset position, Offset position,
List<TextSelectionPoint> endpoints, List<TextSelectionPoint> endpoints,
TextSelectionDelegate delegate, TextSelectionDelegate delegate,
ValueListenable<ClipboardStatus>? clipboardStatus, ClipboardStatusNotifier clipboardStatus,
Offset? lastSecondaryTapDownPosition, Offset? lastSecondaryTapDownPosition,
) { ) {
throw UnimplementedError(); throw UnimplementedError();
...@@ -1199,15 +1221,15 @@ class TextSelectionControlsSpy extends TextSelectionControls { ...@@ -1199,15 +1221,15 @@ class TextSelectionControlsSpy extends TextSelectionControls {
@override @override
Widget buildToolbar( Widget buildToolbar(
BuildContext context, BuildContext context,
Rect globalEditableRegion, Rect globalEditableRegion,
double textLineHeight, double textLineHeight,
Offset position, Offset position,
List<TextSelectionPoint> endpoints, List<TextSelectionPoint> endpoints,
TextSelectionDelegate delegate, TextSelectionDelegate delegate,
ValueListenable<ClipboardStatus>? clipboardStatus, ClipboardStatusNotifier clipboardStatus,
Offset? lastSecondaryTapDownPosition, Offset? lastSecondaryTapDownPosition,
) { ) {
return Text('dummy', key: toolBarKey); return Text('dummy', key: toolBarKey);
} }
...@@ -1225,6 +1247,9 @@ class TextSelectionControlsSpy extends TextSelectionControls { ...@@ -1225,6 +1247,9 @@ class TextSelectionControlsSpy extends TextSelectionControls {
class FakeClipboardStatusNotifier extends ClipboardStatusNotifier { class FakeClipboardStatusNotifier extends ClipboardStatusNotifier {
FakeClipboardStatusNotifier() : super(value: ClipboardStatus.unknown); FakeClipboardStatusNotifier() : super(value: ClipboardStatus.unknown);
@override
bool get disposed => false;
bool updateCalled = false; bool updateCalled = false;
@override @override
Future<void> update() async { Future<void> update() async {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment