From e4342184be70d4eaeb4f100e75b068f227172c1b Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Tue, 10 May 2016 13:40:55 -0400 Subject: [PATCH] Use mojo clipboard service for copy/paste toolbar. (#3778) * Use mojo clipboard service for copy/paste toolbar. BUG=https://github.com/flutter/flutter/issues/1567 --- packages/flutter/lib/services.dart | 1 + .../lib/src/material/text_selection.dart | 26 ++++++++------ .../flutter/lib/src/services/clipboard.dart | 35 +++++++++++++++++++ .../lib/src/widgets/text_selection.dart | 17 --------- packages/flutter/test/widget/input_test.dart | 16 +++++++++ 5 files changed, 68 insertions(+), 27 deletions(-) create mode 100644 packages/flutter/lib/src/services/clipboard.dart diff --git a/packages/flutter/lib/services.dart b/packages/flutter/lib/services.dart index 149c4a0edc0..b5faf4163cd 100644 --- a/packages/flutter/lib/services.dart +++ b/packages/flutter/lib/services.dart @@ -18,6 +18,7 @@ export 'src/services/activity.dart'; export 'src/services/app_messages.dart'; export 'src/services/asset_bundle.dart'; export 'src/services/binding.dart'; +export 'src/services/clipboard.dart'; export 'src/services/haptic_feedback.dart'; export 'src/services/image_cache.dart'; export 'src/services/image_decoder.dart'; diff --git a/packages/flutter/lib/src/material/text_selection.dart b/packages/flutter/lib/src/material/text_selection.dart index 8e483bfd408..71e4e3bdba8 100644 --- a/packages/flutter/lib/src/material/text_selection.dart +++ b/packages/flutter/lib/src/material/text_selection.dart @@ -2,9 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:async'; import 'dart:math' as math; import 'package:flutter/widgets.dart'; +import 'package:flutter/services.dart'; import 'flat_button.dart'; import 'icon_button.dart'; @@ -32,8 +34,9 @@ class _TextSelectionToolbar extends StatelessWidget { } items.add(new FlatButton( child: new Text('PASTE'), - onPressed: delegate.pasteBuffer != null ? _handlePaste : null) - ); + // TODO(mpcomplete): This should probably be grayed-out if there is nothing to paste. + onPressed: _handlePaste + )); if (value.selection.isCollapsed) { items.add(new FlatButton(child: new Text('SELECT ALL'), onPressed: _handleSelectAll)); } @@ -50,8 +53,7 @@ class _TextSelectionToolbar extends StatelessWidget { } void _handleCut() { - InputValue value = this.value; - delegate.pasteBuffer = value.selection.textInside(value.text); + Clipboard.setClipboardData(new ClipboardData()..text = value.selection.textInside(value.text)); delegate.inputValue = new InputValue( text: value.selection.textBefore(value.text) + value.selection.textAfter(value.text), selection: new TextSelection.collapsed(offset: value.selection.start) @@ -60,7 +62,7 @@ class _TextSelectionToolbar extends StatelessWidget { } void _handleCopy() { - delegate.pasteBuffer = value.selection.textInside(value.text); + Clipboard.setClipboardData(new ClipboardData()..text = value.selection.textInside(value.text)); delegate.inputValue = new InputValue( text: value.text, selection: new TextSelection.collapsed(offset: value.selection.end) @@ -68,11 +70,15 @@ class _TextSelectionToolbar extends StatelessWidget { delegate.hideToolbar(); } - void _handlePaste() { - delegate.inputValue = new InputValue( - text: value.selection.textBefore(value.text) + delegate.pasteBuffer + value.selection.textAfter(value.text), - selection: new TextSelection.collapsed(offset: value.selection.start + delegate.pasteBuffer.length) - ); + Future _handlePaste() async { + InputValue value = this.value; // Snapshot the input before using `await`. + ClipboardData clip = await Clipboard.getClipboardData(Clipboard.kTextPlain); + if (clip != null) { + delegate.inputValue = new InputValue( + text: value.selection.textBefore(value.text) + clip.text + value.selection.textAfter(value.text), + selection: new TextSelection.collapsed(offset: value.selection.start + clip.text.length) + ); + } delegate.hideToolbar(); } diff --git a/packages/flutter/lib/src/services/clipboard.dart b/packages/flutter/lib/src/services/clipboard.dart new file mode 100644 index 00000000000..6eeabfbb909 --- /dev/null +++ b/packages/flutter/lib/src/services/clipboard.dart @@ -0,0 +1,35 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:sky_services/editing/editing.mojom.dart' as mojom; + +import 'shell.dart'; + +export 'package:sky_services/editing/editing.mojom.dart' show ClipboardData; + +mojom.ClipboardProxy _initClipboardProxy() { + mojom.ClipboardProxy proxy = new mojom.ClipboardProxy.unbound(); + shell.connectToService('mojo:clipboard', proxy); + return proxy; +} + +final mojom.ClipboardProxy _clipboardProxy = _initClipboardProxy(); + +/// An interface to the system's clipboard. Wraps the mojo interface. +class Clipboard { + /// Constants for common [getClipboardData] [format] types. + static final String kTextPlain = 'text/plain'; + + Clipboard._(); + + static void setClipboardData(mojom.ClipboardData clip) { + _clipboardProxy.ptr.setClipboardData(clip); + } + + static Future getClipboardData(String format) async { + return (await _clipboardProxy.ptr.getClipboardData(format)).clip; + } +} diff --git a/packages/flutter/lib/src/widgets/text_selection.dart b/packages/flutter/lib/src/widgets/text_selection.dart index 8243ed718f5..1aa234ca284 100644 --- a/packages/flutter/lib/src/widgets/text_selection.dart +++ b/packages/flutter/lib/src/widgets/text_selection.dart @@ -42,19 +42,10 @@ abstract class TextSelectionDelegate { /// Sets the current text input (replaces the whole line). void set inputValue(InputValue value); - /// The copy/paste buffer. Application-wide. - String get pasteBuffer; - - /// Sets the copy/paste buffer. - void set pasteBuffer(String value); - /// Hides the text selection toolbar. void hideToolbar(); } -// TODO(mpcomplete): need to interact with the system clipboard. -String _pasteBuffer; - /// Manages a pair of text selection handles to be shown in an Overlay /// containing the owning widget. class TextSelectionOverlay implements TextSelectionDelegate { @@ -162,14 +153,6 @@ class TextSelectionOverlay implements TextSelectionDelegate { onSelectionOverlayChanged(value); } - @override - String get pasteBuffer => _pasteBuffer; - - @override - void set pasteBuffer(String value) { - _pasteBuffer = value; - } - @override void hideToolbar() { hide(); diff --git a/packages/flutter/test/widget/input_test.dart b/packages/flutter/test/widget/input_test.dart index eca419d0460..b46021a8b00 100644 --- a/packages/flutter/test/widget/input_test.dart +++ b/packages/flutter/test/widget/input_test.dart @@ -26,9 +26,25 @@ class MockKeyboard implements mojom.Keyboard { void setEditingState(mojom.EditingState state) {} } +class MockClipboard implements mojom.Clipboard { + mojom.ClipboardData _clip; + + @override + void setClipboardData(mojom.ClipboardData clip) { + _clip = clip; + } + + @override + dynamic getClipboardData(String format,[Function responseFactory = null]) { + return new mojom.ClipboardGetClipboardDataResponseParams()..clip = _clip; + } +} + void main() { MockKeyboard mockKeyboard = new MockKeyboard(); serviceMocker.registerMockService(mojom.Keyboard.serviceName, mockKeyboard); + MockClipboard mockClipboard = new MockClipboard(); + serviceMocker.registerMockService(mojom.Clipboard.serviceName, mockClipboard); void enterText(String testValue) { // Simulate entry of text through the keyboard.