@@ -8,6 +8,7 @@ import 'dart:ui' as ui;
8
8
9
9
import 'package:flutter/widgets.dart' ;
10
10
import 'package:flutter/rendering.dart' ;
11
+ import 'package:flutter/services.dart' ;
11
12
12
13
import 'button.dart' ;
13
14
import 'colors.dart' ;
@@ -62,6 +63,151 @@ const TextStyle _kToolbarButtonDisabledFontStyle = TextStyle(
62
63
// Eyeballed value.
63
64
const EdgeInsets _kToolbarButtonPadding = EdgeInsets .symmetric (vertical: 10.0 , horizontal: 18.0 );
64
65
66
+ // Generates the child that's passed into CupertinoTextSelectionToolbar.
67
+ class _CupertinoTextSelectionToolbarWrapper extends StatefulWidget {
68
+ const _CupertinoTextSelectionToolbarWrapper ({
69
+ Key key,
70
+ this .arrowTipX,
71
+ this .barTopY,
72
+ this .clipboardStatus,
73
+ this .handleCut,
74
+ this .handleCopy,
75
+ this .handlePaste,
76
+ this .handleSelectAll,
77
+ this .isArrowPointingDown,
78
+ }) : super (key: key);
79
+
80
+ final double arrowTipX;
81
+ final double barTopY;
82
+ final ClipboardStatusNotifier clipboardStatus;
83
+ final VoidCallback handleCut;
84
+ final VoidCallback handleCopy;
85
+ final VoidCallback handlePaste;
86
+ final VoidCallback handleSelectAll;
87
+ final bool isArrowPointingDown;
88
+
89
+ @override
90
+ _CupertinoTextSelectionToolbarWrapperState createState () => _CupertinoTextSelectionToolbarWrapperState ();
91
+ }
92
+
93
+ class _CupertinoTextSelectionToolbarWrapperState extends State <_CupertinoTextSelectionToolbarWrapper > {
94
+ ClipboardStatusNotifier _clipboardStatus;
95
+
96
+ void _onChangedClipboardStatus () {
97
+ setState (() {
98
+ // Inform the widget that the value of clipboardStatus has changed.
99
+ });
100
+ }
101
+
102
+ @override
103
+ void initState () {
104
+ super .initState ();
105
+ _clipboardStatus = widget.clipboardStatus ?? ClipboardStatusNotifier ();
106
+ _clipboardStatus.addListener (_onChangedClipboardStatus);
107
+ _clipboardStatus.update ();
108
+ }
109
+
110
+ @override
111
+ void didUpdateWidget (_CupertinoTextSelectionToolbarWrapper oldWidget) {
112
+ super .didUpdateWidget (oldWidget);
113
+ if (oldWidget.clipboardStatus == null && widget.clipboardStatus != null ) {
114
+ _clipboardStatus.removeListener (_onChangedClipboardStatus);
115
+ _clipboardStatus.dispose ();
116
+ _clipboardStatus = widget.clipboardStatus;
117
+ } else if (oldWidget.clipboardStatus != null ) {
118
+ if (widget.clipboardStatus == null ) {
119
+ _clipboardStatus = ClipboardStatusNotifier ();
120
+ _clipboardStatus.addListener (_onChangedClipboardStatus);
121
+ oldWidget.clipboardStatus.removeListener (_onChangedClipboardStatus);
122
+ } else if (widget.clipboardStatus != oldWidget.clipboardStatus) {
123
+ _clipboardStatus = widget.clipboardStatus;
124
+ _clipboardStatus.addListener (_onChangedClipboardStatus);
125
+ oldWidget.clipboardStatus.removeListener (_onChangedClipboardStatus);
126
+ }
127
+ }
128
+ if (widget.handlePaste != null ) {
129
+ _clipboardStatus.update ();
130
+ }
131
+ }
132
+
133
+ @override
134
+ void dispose () {
135
+ super .dispose ();
136
+ // When used in an Overlay, this can be disposed after its creator has
137
+ // already disposed _clipboardStatus.
138
+ if (! _clipboardStatus.disposed) {
139
+ _clipboardStatus.removeListener (_onChangedClipboardStatus);
140
+ if (widget.clipboardStatus == null ) {
141
+ _clipboardStatus.dispose ();
142
+ }
143
+ }
144
+ }
145
+
146
+ @override
147
+ Widget build (BuildContext context) {
148
+ // Don't render the menu until the state of the clipboard is known.
149
+ if (widget.handlePaste != null
150
+ && _clipboardStatus.value == ClipboardStatus .unknown) {
151
+ return const SizedBox (width: 0.0 , height: 0.0 );
152
+ }
153
+
154
+ final List <Widget > items = < Widget > [];
155
+ final CupertinoLocalizations localizations = CupertinoLocalizations .of (context);
156
+ final EdgeInsets arrowPadding = widget.isArrowPointingDown
157
+ ? EdgeInsets .only (bottom: _kToolbarArrowSize.height)
158
+ : EdgeInsets .only (top: _kToolbarArrowSize.height);
159
+ final Widget onePhysicalPixelVerticalDivider =
160
+ SizedBox (width: 1.0 / MediaQuery .of (context).devicePixelRatio);
161
+
162
+ void addToolbarButton (
163
+ String text,
164
+ VoidCallback onPressed,
165
+ ) {
166
+ if (items.isNotEmpty) {
167
+ items.add (onePhysicalPixelVerticalDivider);
168
+ }
169
+
170
+ items.add (CupertinoButton (
171
+ child: Text (
172
+ text,
173
+ overflow: TextOverflow .ellipsis,
174
+ style: _kToolbarButtonFontStyle,
175
+ ),
176
+ borderRadius: null ,
177
+ color: _kToolbarBackgroundColor,
178
+ minSize: _kToolbarHeight,
179
+ onPressed: onPressed,
180
+ padding: _kToolbarButtonPadding.add (arrowPadding),
181
+ pressedOpacity: 0.7 ,
182
+ ));
183
+ }
184
+
185
+ if (widget.handleCut != null ) {
186
+ addToolbarButton (localizations.cutButtonLabel, widget.handleCut);
187
+ }
188
+ if (widget.handleCopy != null ) {
189
+ addToolbarButton (localizations.copyButtonLabel, widget.handleCopy);
190
+ }
191
+ if (widget.handlePaste != null
192
+ && _clipboardStatus.value == ClipboardStatus .pasteable) {
193
+ addToolbarButton (localizations.pasteButtonLabel, widget.handlePaste);
194
+ }
195
+ if (widget.handleSelectAll != null ) {
196
+ addToolbarButton (localizations.selectAllButtonLabel, widget.handleSelectAll);
197
+ }
198
+
199
+ return CupertinoTextSelectionToolbar ._(
200
+ barTopY: widget.barTopY,
201
+ arrowTipX: widget.arrowTipX,
202
+ isArrowPointingDown: widget.isArrowPointingDown,
203
+ child: items.isEmpty ? null : _CupertinoTextSelectionToolbarContent (
204
+ isArrowPointingDown: widget.isArrowPointingDown,
205
+ children: items,
206
+ ),
207
+ );
208
+ }
209
+ }
210
+
65
211
/// An iOS-style toolbar that appears in response to text selection.
66
212
///
67
213
/// Typically displays buttons for text manipulation, e.g. copying and pasting text.
@@ -312,6 +458,7 @@ class _CupertinoTextSelectionControls extends TextSelectionControls {
312
458
Offset position,
313
459
List <TextSelectionPoint > endpoints,
314
460
TextSelectionDelegate delegate,
461
+ ClipboardStatusNotifier clipboardStatus,
315
462
) {
316
463
assert (debugCheckHasMediaQuery (context));
317
464
final MediaQueryData mediaQuery = MediaQuery .of (context);
@@ -338,49 +485,15 @@ class _CupertinoTextSelectionControls extends TextSelectionControls {
338
485
? endpoints.first.point.dy - textLineHeight - _kToolbarContentDistance - _kToolbarHeight
339
486
: endpoints.last.point.dy + _kToolbarContentDistance;
340
487
341
- final List <Widget > items = < Widget > [];
342
- final CupertinoLocalizations localizations = CupertinoLocalizations .of (context);
343
- final EdgeInsets arrowPadding = isArrowPointingDown
344
- ? EdgeInsets .only (bottom: _kToolbarArrowSize.height)
345
- : EdgeInsets .only (top: _kToolbarArrowSize.height);
346
-
347
- void addToolbarButtonIfNeeded (
348
- String text,
349
- bool Function (TextSelectionDelegate ) predicate,
350
- void Function (TextSelectionDelegate ) onPressed,
351
- ) {
352
- if (! predicate (delegate)) {
353
- return ;
354
- }
355
-
356
- items.add (CupertinoButton (
357
- child: Text (
358
- text,
359
- overflow: TextOverflow .ellipsis,
360
- style: _kToolbarButtonFontStyle,
361
- ),
362
- color: _kToolbarBackgroundColor,
363
- minSize: _kToolbarHeight,
364
- padding: _kToolbarButtonPadding.add (arrowPadding),
365
- borderRadius: null ,
366
- pressedOpacity: 0.7 ,
367
- onPressed: () => onPressed (delegate),
368
- ));
369
- }
370
-
371
- addToolbarButtonIfNeeded (localizations.cutButtonLabel, canCut, handleCut);
372
- addToolbarButtonIfNeeded (localizations.copyButtonLabel, canCopy, handleCopy);
373
- addToolbarButtonIfNeeded (localizations.pasteButtonLabel, canPaste, handlePaste);
374
- addToolbarButtonIfNeeded (localizations.selectAllButtonLabel, canSelectAll, handleSelectAll);
375
-
376
- return CupertinoTextSelectionToolbar ._(
377
- barTopY: localBarTopY + globalEditableRegion.top,
488
+ return _CupertinoTextSelectionToolbarWrapper (
378
489
arrowTipX: arrowTipX,
490
+ barTopY: localBarTopY + globalEditableRegion.top,
491
+ clipboardStatus: clipboardStatus,
492
+ handleCut: canCut (delegate) ? () => handleCut (delegate) : null ,
493
+ handleCopy: canCopy (delegate) ? () => handleCopy (delegate, clipboardStatus) : null ,
494
+ handlePaste: canPaste (delegate) ? () => handlePaste (delegate) : null ,
495
+ handleSelectAll: canSelectAll (delegate) ? () => handleSelectAll (delegate) : null ,
379
496
isArrowPointingDown: isArrowPointingDown,
380
- child: items.isEmpty ? null : _CupertinoTextSelectionToolbarContent (
381
- isArrowPointingDown: isArrowPointingDown,
382
- children: items,
383
- ),
384
497
);
385
498
}
386
499
0 commit comments