Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
88cf68c8
Commit
88cf68c8
authored
Oct 18, 2016
by
Adam Barth
Committed by
GitHub
Oct 18, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Migrate Clipboard to platform messages (#6367)
The platform plugin now supports clipboard operations.
parent
50ebcd1d
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
118 additions
and
69 deletions
+118
-69
text_selection.dart
packages/flutter/lib/src/material/text_selection.dart
+6
-6
clipboard.dart
packages/flutter/lib/src/services/clipboard.dart
+29
-19
platform_messages.dart
packages/flutter/lib/src/services/platform_messages.dart
+65
-28
input_test.dart
packages/flutter/test/widget/input_test.dart
+18
-16
No files found.
packages/flutter/lib/src/material/text_selection.dart
View file @
88cf68c8
...
...
@@ -50,7 +50,7 @@ class _TextSelectionToolbar extends StatelessWidget {
}
void
_handleCut
()
{
Clipboard
.
set
ClipboardData
(
new
ClipboardData
()..
text
=
value
.
selection
.
textInside
(
value
.
text
));
Clipboard
.
set
Data
(
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
)
...
...
@@ -59,7 +59,7 @@ class _TextSelectionToolbar extends StatelessWidget {
}
void
_handleCopy
()
{
Clipboard
.
set
ClipboardData
(
new
ClipboardData
()..
text
=
value
.
selection
.
textInside
(
value
.
text
));
Clipboard
.
set
Data
(
new
ClipboardData
(
text:
value
.
selection
.
textInside
(
value
.
text
)
));
delegate
.
inputValue
=
new
InputValue
(
text:
value
.
text
,
selection:
new
TextSelection
.
collapsed
(
offset:
value
.
selection
.
end
)
...
...
@@ -69,11 +69,11 @@ class _TextSelectionToolbar extends StatelessWidget {
Future
<
Null
>
_handlePaste
()
async
{
InputValue
value
=
this
.
value
;
// Snapshot the input before using `await`.
ClipboardData
clip
=
await
Clipboard
.
getClipboard
Data
(
Clipboard
.
kTextPlain
);
if
(
clip
!=
null
)
{
ClipboardData
data
=
await
Clipboard
.
get
Data
(
Clipboard
.
kTextPlain
);
if
(
data
!=
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
)
text:
value
.
selection
.
textBefore
(
value
.
text
)
+
data
.
text
+
value
.
selection
.
textAfter
(
value
.
text
),
selection:
new
TextSelection
.
collapsed
(
offset:
value
.
selection
.
start
+
data
.
text
.
length
)
);
}
delegate
.
hideToolbar
();
...
...
packages/flutter/lib/src/services/clipboard.dart
View file @
88cf68c8
...
...
@@ -4,38 +4,48 @@
import
'dart:async'
;
import
'package:flutter_services/editing.dart'
as
mojom
;
import
'shell.dart'
;
export
'package:flutter_services/editing.dart'
show
ClipboardData
;
mojom
.
ClipboardProxy
_initClipboardProxy
(
)
{
return
shell
.
connectToApplicationService
(
'mojo:clipboard'
,
mojom
.
Clipboard
.
connectToService
);
import
'platform_messages.dart'
;
/// Data stored on the system clip board.
///
/// The system clip board can contain data of various media types. This data
/// structure currently supports only plain text data in the [text] property.
class
ClipboardData
{
/// Creates data for the system clipboard.
const
ClipboardData
({
this
.
text
});
/// Plain text data on the clip board.
final
String
text
;
}
final
mojom
.
ClipboardProxy
_clipboardProxy
=
_initClipboardProxy
();
/// An interface to the system's clipboard. Wraps the mojo interface.
/// An interface to the system's clipboard.
class
Clipboard
{
/// Constants for common [get
Clipboard
Data] [format] types.
/// Constants for common [getData] [format] types.
static
final
String
kTextPlain
=
'text/plain'
;
Clipboard
.
_
();
/// Stores the given clipboard data on the clipboard.
static
void
setClipboardData
(
mojom
.
ClipboardData
clip
)
{
_clipboardProxy
.
setClipboardData
(
clip
);
static
Future
<
Null
>
setData
(
ClipboardData
data
)
async
{
await
PlatformMessages
.
sendJSON
(
'flutter/platform'
,
<
String
,
dynamic
>{
'method'
:
'Clipboard.setData'
,
'args'
:
<
Map
<
String
,
dynamic
>>[<
String
,
dynamic
>{
'text'
:
data
.
text
,
}],
});
}
/// Retrieves data from the clipboard that matches the given format.
///
/// * `format` is a media type, such as `text/plain`.
static
Future
<
mojom
.
ClipboardData
>
getClipboardData
(
String
format
)
{
Completer
<
mojom
.
ClipboardData
>
completer
=
new
Completer
<
mojom
.
ClipboardData
>();
_clipboardProxy
.
getClipboardData
(
format
,
(
mojom
.
ClipboardData
clip
)
{
completer
.
complete
(
clip
);
static
Future
<
ClipboardData
>
getData
(
String
format
)
async
{
Map
<
String
,
dynamic
>
result
=
await
PlatformMessages
.
sendJSON
(
'flutter/platform'
,
<
String
,
dynamic
>{
'method'
:
'Clipboard.getData'
,
'args'
:
<
String
>[
format
],
});
return
completer
.
future
;
if
(
result
==
null
)
return
null
;
return
new
ClipboardData
(
text:
result
[
'text'
]);
}
}
packages/flutter/lib/src/services/platform_messages.dart
View file @
88cf68c8
...
...
@@ -28,29 +28,35 @@ dynamic _decodeJSON(String message) {
return
message
!=
null
?
JSON
.
decode
(
message
)
:
null
;
}
void
_sendString
(
String
name
,
String
message
,
void
callback
(
String
reply
))
{
Uint8List
encoded
=
UTF8
.
encoder
.
convert
(
message
);
ui
.
window
.
sendPlatformMessage
(
name
,
encoded
.
buffer
.
asByteData
(),
(
ByteData
reply
)
{
try
{
callback
(
_decodeUTF8
(
reply
));
}
catch
(
exception
,
stack
)
{
FlutterError
.
reportError
(
new
FlutterErrorDetails
(
exception:
exception
,
stack:
stack
,
library
:
'services library'
,
context:
'during a platform message response callback'
,
));
}
});
}
typedef
Future
<
ByteData
>
_PlatformMessageHandler
(
ByteData
message
);
/// Sends message to and receives messages from the underlying platform.
class
PlatformMessages
{
/// Handlers for incoming platform messages.
static
final
Map
<
String
,
_PlatformMessageHandler
>
_handlers
=
<
String
,
_PlatformMessageHandler
>{};
/// Mock handlers that intercept and respond to outgoing messages.
static
final
Map
<
String
,
_PlatformMessageHandler
>
_mockHandlers
=
<
String
,
_PlatformMessageHandler
>{};
static
Future
<
ByteData
>
_sendPlatformMessage
(
String
name
,
ByteData
message
)
{
final
Completer
<
ByteData
>
completer
=
new
Completer
<
ByteData
>();
ui
.
window
.
sendPlatformMessage
(
name
,
message
,
(
ByteData
reply
)
{
try
{
completer
.
complete
(
reply
);
}
catch
(
exception
,
stack
)
{
FlutterError
.
reportError
(
new
FlutterErrorDetails
(
exception:
exception
,
stack:
stack
,
library
:
'services library'
,
context:
'during a platform message response callback'
,
));
}
});
return
completer
.
future
;
}
/// Calls the handler registered for the given name.
///
/// Typically called by [ServicesBinding] to handle platform messages received
...
...
@@ -77,22 +83,22 @@ class PlatformMessages {
}
}
/// Send a binary message to the host application.
static
Future
<
ByteData
>
sendBinary
(
String
name
,
ByteData
message
)
{
final
_PlatformMessageHandler
handler
=
_mockHandlers
[
name
];
if
(
handler
!=
null
)
return
handler
(
message
);
return
_sendPlatformMessage
(
name
,
message
);
}
/// Send a string message to the host application.
static
Future
<
String
>
sendString
(
String
name
,
String
message
)
{
Completer
<
String
>
completer
=
new
Completer
<
String
>();
_sendString
(
name
,
message
,
(
String
reply
)
{
completer
.
complete
(
reply
);
});
return
completer
.
future
;
static
Future
<
String
>
sendString
(
String
name
,
String
message
)
async
{
return
_decodeUTF8
(
await
sendBinary
(
name
,
_encodeUTF8
(
message
)));
}
/// Sends a JSON-encoded message to the host application and JSON-decodes the response.
static
Future
<
dynamic
>
sendJSON
(
String
name
,
dynamic
json
)
{
Completer
<
dynamic
>
completer
=
new
Completer
<
dynamic
>();
_sendString
(
name
,
JSON
.
encode
(
json
),
(
String
reply
)
{
completer
.
complete
(
_decodeJSON
(
reply
));
});
return
completer
.
future
;
static
Future
<
dynamic
>
sendJSON
(
String
name
,
dynamic
json
)
async
{
return
_decodeJSON
(
await
sendString
(
name
,
_encodeJSON
(
json
)));
}
/// Set a callback for receiving binary messages from the platform.
...
...
@@ -123,4 +129,35 @@ class PlatformMessages {
return
_encodeJSON
(
await
handler
(
_decodeJSON
(
message
)));
});
}
/// Sets a message handler that intercepts outgoing messages in binary form.
///
/// The given callback will replace the currently registered callback (if any).
/// To remove the mock handler, pass `null` as the `handler` argument.
static
void
setMockBinaryMessageHandler
(
String
name
,
Future
<
ByteData
>
handler
(
ByteData
message
))
{
if
(
handler
==
null
)
_mockHandlers
.
remove
(
handler
);
else
_mockHandlers
[
name
]
=
handler
;
}
/// Sets a message handler that intercepts outgoing messages in string form.
///
/// The given callback will replace the currently registered callback (if any).
/// To remove the mock handler, pass `null` as the `handler` argument.
static
void
setMockStringMessageHandler
(
String
name
,
Future
<
String
>
handler
(
String
message
))
{
setMockBinaryMessageHandler
(
name
,
(
ByteData
message
)
async
{
return
_encodeUTF8
(
await
handler
(
_decodeUTF8
(
message
)));
});
}
/// Sets a message handler that intercepts outgoing messages in JSON form.
///
/// The given callback will replace the currently registered callback (if any).
/// To remove the mock handler, pass `null` as the `handler` argument.
static
void
setMockJSONMessageHandler
(
String
name
,
Future
<
dynamic
>
handler
(
dynamic
message
))
{
setMockStringMessageHandler
(
name
,
(
String
message
)
async
{
return
_encodeJSON
(
await
handler
(
_decodeJSON
(
message
)));
});
}
}
packages/flutter/test/widget/input_test.dart
View file @
88cf68c8
...
...
@@ -7,6 +7,7 @@ import 'dart:async';
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_services/editing.dart'
as
mojom
;
import
'package:meta/meta.dart'
;
...
...
@@ -30,29 +31,30 @@ class MockKeyboard extends mojom.KeyboardProxy {
void
setEditingState
(
mojom
.
EditingState
state
)
{}
}
class
MockClipboard
extends
mojom
.
ClipboardProxy
{
MockClipboard
()
:
super
.
unbound
();
mojom
.
ClipboardData
_clip
;
@override
void
setClipboardData
(
mojom
.
ClipboardData
clip
)
{
_clip
=
clip
;
}
@override
void
getClipboardData
(
String
format
,
void
callback
(
mojom
.
ClipboardData
clip
))
{
scheduleMicrotask
(()
{
callback
(
_clip
)
;
}
);
class
MockClipboard
{
Object
_clipboardData
=
<
String
,
dynamic
>{
'text'
:
null
}
;
Future
<
dynamic
>
handleJSONMessage
(
dynamic
json
)
async
{
final
String
method
=
json
[
'method'
];
final
List
<
dynamic
>
args
=
json
[
'args'
]
;
switch
(
method
)
{
case
'Clipboard.getData'
:
return
_clipboardData
;
case
'Clipboard.setData'
:
_clipboardData
=
args
[
0
];
break
;
}
}
}
void
main
(
)
{
MockKeyboard
mockKeyboard
=
new
MockKeyboard
();
serviceMocker
.
registerMockService
(
mockKeyboard
);
MockClipboard
mockClipboard
=
new
MockClipboard
();
serviceMocker
.
registerMockService
(
mockClipboard
);
PlatformMessages
.
setMockJSONMessageHandler
(
'flutter/platform'
,
mockClipboard
.
handleJSONMessage
);
const
String
kThreeLines
=
'First line of text is here abcdef ghijkl mnopqrst. '
+
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment