showNativeContextMenu function

Future<List<int>?> showNativeContextMenu(
  1. BuildContext context, {
  2. required List<CNPopupMenuEntry> items,
  3. required Offset globalPosition,
})

Shows items as a native menu at globalPosition (Flutter's global logical coordinates) and returns the path of the chosen item, or null when the menu was closed without a choice.

  • macOS: an NSMenu with its top-left corner at the position, as a context menu opens.
  • iOS 17.4+: the UIMenu a button's menu is, opened from the position.
  • Elsewhere, below iOS 17.4, or when the native side is missing: the CupertinoActionSheet fallback of CNPopupMenuButton.

Used by CNContextMenu and by CNPopupGesture's secondary click.

Implementation

Future<List<int>?> showNativeContextMenu(
  BuildContext context, {
  required List<CNPopupMenuEntry> items,
  required Offset globalPosition,
}) async {
  if (items.isEmpty) return null;
  final platform = defaultTargetPlatform;
  if (platform != TargetPlatform.iOS && platform != TargetPlatform.macOS) {
    return showPopupMenuFallbackSheet(context, items);
  }

  final (iconBytes, assetPaths) = await _menuVisuals(items);
  if (!context.mounted) return null;

  final payload = debugBuildContextMenuPayload(
    items: items,
    position: globalPosition,
    resolveColor: (c) => resolveColorToArgb(c, context),
    isDark: ThemeHelper.themeIsDark(context),
    customIconBytes: iconBytes,
    assetPaths: assetPaths,
  );

  try {
    final path = await _channel.invokeListMethod<int>('show', payload);
    if (path == null || path.isEmpty) return null;
    return path;
  } on PlatformException catch (e) {
    if (e.code == 'unavailable' && context.mounted) {
      // iOS before 17.4 cannot open a menu without a touch on its button.
      return showPopupMenuFallbackSheet(context, items);
    }
    debugPrint(
      '⚠️ [cupertino_native_better] context menu failed: ${e.code} '
      '${e.message ?? ''}',
    );
    return null;
  } on MissingPluginException {
    // No native side (a test without a mock handler, or an older plugin
    // build): the menu is still shown, by the fallback.
    if (!context.mounted) return null;
    return showPopupMenuFallbackSheet(context, items);
  }
}