diff --git a/packages/flutter/lib/services.dart b/packages/flutter/lib/services.dart index 149c4a0edc..b5faf4163c 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 8e483bfd40..71e4e3bdba 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 0000000000..6eeabfbb90 --- /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 8243ed718f..1aa234ca28 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 eca419d046..b46021a8b0 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.