Skip to content

Commit df65e46

Browse files
Secure paste milestone 2 (#159013)
Implements the framework side of secure paste milestone 2, where the iOS system context menu items can be customized. Depends on PR flutter/flutter#161103. Currently I've merged that PR into this one for testing, but I think that PR should merge separately first. ### Widget API (most users) ```dart TextField( contextMenuBuilder: (BuildContext context, EditableTextState editableTextState) { return SystemContextMenu.editableText( editableTextState: editableTextState, // items is optional items: <IOSSystemContextMenuItem>[ const IOSSystemContextMenuItemCut(), constIOS SystemContextMenuItemCopy(), const IOSSystemContextMenuItemPaste(), const IOSSystemContextMenuItemSelectAll(), const IOSSystemContextMenuItemSearchWeb( title: 'Search!', // title is optional for this button, defaults to localized string ), // Milestone 3: IOSSystemContextMenuItemCustom( // title and onPressed are required title: 'custom button', onPressed: () { print('pressed the custom button.'); } ), ], ); }, ), ``` ### Raw Controller API ```dart _systemContextMenuController.show( widget.anchor, <IOSSystemContextMenuItemData>[ // Notice these are different classes than those used for the widget. That's // mainly because I can't provide localized defaults here, so the titles are // required in the classes that have titles. const IOSSystemContextMenuItemDataCut(), const IOSSystemContextMenuItemDataCopy(), const IOSSystemContextMenuItemDataPaste(), const IOSSystemContextMenuItemDataSelectAll(), const IOSSystemContextMenuItemDataSearchWeb( title: 'Search!', // title is required. ), // Milestone 3: IOSSystemContextMenuItemDataCustom( // title and onPressed are required as before. title: 'custom button', onPressed: () { print('pressed the custom button.'); } ), ], ); ``` <details> <summary>Json format</summary> ```dart return _channel.invokeMethod<Map<String, dynamic>>( 'ContextMenu.showSystemContextMenu', <String, dynamic>{ 'targetRect': <String, double>{ 'x': targetRect.left, 'y': targetRect.top, 'width': targetRect.width, 'height': targetRect.height, }, 'items': <dynamic>[ <String, dynamic>{ 'type': 'default', 'action': 'paste', }, <String, dynamic>{ 'type': 'default', 'action': 'copy', }, <String, dynamic>{ 'type': 'default', 'title': 'Crazy Title', 'action': 'share', }, ], }, ); ``` </summary> </details> ### Localization changes This change requires the SystemContextMenu widget in the widgets library to be able to look up the default localized label for several context menu buttons like "Copy", etc. Those strings previously resided in MaterialLocalizations and CupertinoLocalizations, but not in WidgetsLocalizations, so I have copied the necessary strings into WidgetsLocalizations. --------- Co-authored-by: Huan Lin <hellohuanlin@gmail.com>
1 parent 043b719 commit df65e46

File tree

124 files changed

+4034
-309
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

124 files changed

+4034
-309
lines changed

packages/flutter/lib/src/services/binding.dart

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -413,9 +413,15 @@ mixin ServicesBinding on BindingBase, SchedulerBinding {
413413
// the user taps outside the menu. Not called when Flutter shows a new
414414
// system context menu while an old one is still visible.
415415
case 'ContextMenu.onDismissSystemContextMenu':
416-
for (final SystemContextMenuClient client in _systemContextMenuClients) {
417-
client.handleSystemHide();
416+
if (_systemContextMenuClient == null) {
417+
assert(
418+
false,
419+
'Platform sent onDismissSystemContextMenu when no SystemContextMenuClient was registered.',
420+
);
421+
return;
418422
}
423+
_systemContextMenuClient!.handleSystemHide();
424+
_systemContextMenuClient = null;
419425
case 'SystemChrome.systemUIChange':
420426
final List<dynamic> args = methodCall.arguments as List<dynamic>;
421427
if (_systemUiChangeCallback != null) {
@@ -571,17 +577,14 @@ mixin ServicesBinding on BindingBase, SchedulerBinding {
571577
await SystemChannels.platform.invokeMethod('System.initializationComplete');
572578
}
573579

574-
final Set<SystemContextMenuClient> _systemContextMenuClients = <SystemContextMenuClient>{};
580+
SystemContextMenuClient? _systemContextMenuClient;
575581

576582
/// Registers a [SystemContextMenuClient] that will receive system context
577583
/// menu calls from the engine.
578-
static void registerSystemContextMenuClient(SystemContextMenuClient client) {
579-
instance._systemContextMenuClients.add(client);
580-
}
581-
582-
/// Unregisters a [SystemContextMenuClient] so that it is no longer called.
583-
static void unregisterSystemContextMenuClient(SystemContextMenuClient client) {
584-
instance._systemContextMenuClients.remove(client);
584+
///
585+
/// To unregister, set to null.
586+
static set systemContextMenuClient(SystemContextMenuClient? client) {
587+
instance._systemContextMenuClient = client;
585588
}
586589
}
587590

@@ -673,14 +676,17 @@ class _DefaultBinaryMessenger extends BinaryMessenger {
673676
/// See also:
674677
/// * [SystemContextMenuController], which uses this to provide a fully
675678
/// featured way to control the system context menu.
679+
/// * [ServicesBinding.systemContextMenuClient], which can be set to a
680+
/// [SystemContextMenuClient] to register it to receive events, or null to
681+
/// unregister.
676682
/// * [MediaQuery.maybeSupportsShowingSystemContextMenu], which indicates
677683
/// whether the system context menu is supported.
678684
/// * [SystemContextMenu], which provides a widget interface for displaying the
679685
/// system context menu.
680686
mixin SystemContextMenuClient {
681687
/// Handles the system hiding a context menu.
682688
///
683-
/// This is called for all instances of [SystemContextMenuController], so it's
684-
/// not guaranteed that this instance was the one that was hidden.
689+
/// Called only on the single active instance registered with
690+
/// [ServicesBinding.systemContextMenuClient].
685691
void handleSystemHide();
686692
}

0 commit comments

Comments
 (0)