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
This commit is contained in:
parent
770f8f1d0c
commit
e4342184be
@ -18,6 +18,7 @@ export 'src/services/activity.dart';
|
|||||||
export 'src/services/app_messages.dart';
|
export 'src/services/app_messages.dart';
|
||||||
export 'src/services/asset_bundle.dart';
|
export 'src/services/asset_bundle.dart';
|
||||||
export 'src/services/binding.dart';
|
export 'src/services/binding.dart';
|
||||||
|
export 'src/services/clipboard.dart';
|
||||||
export 'src/services/haptic_feedback.dart';
|
export 'src/services/haptic_feedback.dart';
|
||||||
export 'src/services/image_cache.dart';
|
export 'src/services/image_cache.dart';
|
||||||
export 'src/services/image_decoder.dart';
|
export 'src/services/image_decoder.dart';
|
||||||
|
@ -2,9 +2,11 @@
|
|||||||
// 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 'dart:async';
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
import 'flat_button.dart';
|
import 'flat_button.dart';
|
||||||
import 'icon_button.dart';
|
import 'icon_button.dart';
|
||||||
@ -32,8 +34,9 @@ class _TextSelectionToolbar extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
items.add(new FlatButton(
|
items.add(new FlatButton(
|
||||||
child: new Text('PASTE'),
|
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) {
|
if (value.selection.isCollapsed) {
|
||||||
items.add(new FlatButton(child: new Text('SELECT ALL'), onPressed: _handleSelectAll));
|
items.add(new FlatButton(child: new Text('SELECT ALL'), onPressed: _handleSelectAll));
|
||||||
}
|
}
|
||||||
@ -50,8 +53,7 @@ class _TextSelectionToolbar extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _handleCut() {
|
void _handleCut() {
|
||||||
InputValue value = this.value;
|
Clipboard.setClipboardData(new ClipboardData()..text = value.selection.textInside(value.text));
|
||||||
delegate.pasteBuffer = value.selection.textInside(value.text);
|
|
||||||
delegate.inputValue = new InputValue(
|
delegate.inputValue = new InputValue(
|
||||||
text: value.selection.textBefore(value.text) + value.selection.textAfter(value.text),
|
text: value.selection.textBefore(value.text) + value.selection.textAfter(value.text),
|
||||||
selection: new TextSelection.collapsed(offset: value.selection.start)
|
selection: new TextSelection.collapsed(offset: value.selection.start)
|
||||||
@ -60,7 +62,7 @@ class _TextSelectionToolbar extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _handleCopy() {
|
void _handleCopy() {
|
||||||
delegate.pasteBuffer = value.selection.textInside(value.text);
|
Clipboard.setClipboardData(new ClipboardData()..text = value.selection.textInside(value.text));
|
||||||
delegate.inputValue = new InputValue(
|
delegate.inputValue = new InputValue(
|
||||||
text: value.text,
|
text: value.text,
|
||||||
selection: new TextSelection.collapsed(offset: value.selection.end)
|
selection: new TextSelection.collapsed(offset: value.selection.end)
|
||||||
@ -68,11 +70,15 @@ class _TextSelectionToolbar extends StatelessWidget {
|
|||||||
delegate.hideToolbar();
|
delegate.hideToolbar();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handlePaste() {
|
Future<Null> _handlePaste() async {
|
||||||
delegate.inputValue = new InputValue(
|
InputValue value = this.value; // Snapshot the input before using `await`.
|
||||||
text: value.selection.textBefore(value.text) + delegate.pasteBuffer + value.selection.textAfter(value.text),
|
ClipboardData clip = await Clipboard.getClipboardData(Clipboard.kTextPlain);
|
||||||
selection: new TextSelection.collapsed(offset: value.selection.start + delegate.pasteBuffer.length)
|
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();
|
delegate.hideToolbar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
35
packages/flutter/lib/src/services/clipboard.dart
Normal file
35
packages/flutter/lib/src/services/clipboard.dart
Normal file
@ -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<mojom.ClipboardData> getClipboardData(String format) async {
|
||||||
|
return (await _clipboardProxy.ptr.getClipboardData(format)).clip;
|
||||||
|
}
|
||||||
|
}
|
@ -42,19 +42,10 @@ abstract class TextSelectionDelegate {
|
|||||||
/// Sets the current text input (replaces the whole line).
|
/// Sets the current text input (replaces the whole line).
|
||||||
void set inputValue(InputValue value);
|
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.
|
/// Hides the text selection toolbar.
|
||||||
void hideToolbar();
|
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
|
/// Manages a pair of text selection handles to be shown in an Overlay
|
||||||
/// containing the owning widget.
|
/// containing the owning widget.
|
||||||
class TextSelectionOverlay implements TextSelectionDelegate {
|
class TextSelectionOverlay implements TextSelectionDelegate {
|
||||||
@ -162,14 +153,6 @@ class TextSelectionOverlay implements TextSelectionDelegate {
|
|||||||
onSelectionOverlayChanged(value);
|
onSelectionOverlayChanged(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
String get pasteBuffer => _pasteBuffer;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void set pasteBuffer(String value) {
|
|
||||||
_pasteBuffer = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void hideToolbar() {
|
void hideToolbar() {
|
||||||
hide();
|
hide();
|
||||||
|
@ -26,9 +26,25 @@ class MockKeyboard implements mojom.Keyboard {
|
|||||||
void setEditingState(mojom.EditingState state) {}
|
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() {
|
void main() {
|
||||||
MockKeyboard mockKeyboard = new MockKeyboard();
|
MockKeyboard mockKeyboard = new MockKeyboard();
|
||||||
serviceMocker.registerMockService(mojom.Keyboard.serviceName, mockKeyboard);
|
serviceMocker.registerMockService(mojom.Keyboard.serviceName, mockKeyboard);
|
||||||
|
MockClipboard mockClipboard = new MockClipboard();
|
||||||
|
serviceMocker.registerMockService(mojom.Clipboard.serviceName, mockClipboard);
|
||||||
|
|
||||||
void enterText(String testValue) {
|
void enterText(String testValue) {
|
||||||
// Simulate entry of text through the keyboard.
|
// Simulate entry of text through the keyboard.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user