Merge pull request #305 from cogwheel0/improve-cross-platform-image-paste

feat(chat): prevent duplicate paste image context menu options
This commit is contained in:
cogwheel
2025-12-21 08:57:04 +05:30
committed by GitHub

View File

@@ -319,10 +319,9 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
/// Builds a custom context menu with standard options plus "Paste Image". /// Builds a custom context menu with standard options plus "Paste Image".
/// ///
/// The standard paste only works for text. This adds a "Paste Image" /// Adds a "Paste Image" option when there's an image in the clipboard,
/// option that uses the pasteboard package to read images from clipboard /// but only if the system hasn't already provided one (to avoid duplicates
/// on both iOS and Android. The option only appears when there's actually /// on platforms like iOS that may include their own paste image option).
/// an image in the clipboard.
Widget _buildContextMenu( Widget _buildContextMenu(
BuildContext context, BuildContext context,
EditableTextState editableTextState, EditableTextState editableTextState,
@@ -348,27 +347,41 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
final hasImage = imageData != null && imageData.isNotEmpty; final hasImage = imageData != null && imageData.isNotEmpty;
if (hasImage) { if (hasImage) {
// Find the index of the standard Paste button to insert after it // Check if the system already provides a paste image option
final pasteIndex = buttonItems.indexWhere( // (e.g., iOS may include one automatically). Look for any button
(item) => item.type == ContextMenuButtonType.paste, // with a label containing "image" (case-insensitive) to avoid
// adding a duplicate.
final pasteImageLabel =
AppLocalizations.of(context)?.pasteImage ?? 'Paste Image';
final alreadyHasPasteImage = buttonItems.any(
(item) =>
item.label != null &&
item.label!.toLowerCase().contains('image'),
); );
// Capture imageData in closure to avoid re-reading clipboard if (!alreadyHasPasteImage) {
final pasteImageItem = ContextMenuButtonItem( // Find the index of the standard Paste button to insert after it
label: AppLocalizations.of(context)?.pasteImage ?? 'Paste Image', final pasteIndex = buttonItems.indexWhere(
onPressed: () { (item) => item.type == ContextMenuButtonType.paste,
// Close the context menu first );
ContextMenuController.removeAny();
// Use the captured imageData directly
_handleClipboardPasteWithData(imageData);
},
);
// Insert after Paste if found, otherwise add at the end // Capture imageData in closure to avoid re-reading clipboard
if (pasteIndex >= 0) { final pasteImageItem = ContextMenuButtonItem(
buttonItems.insert(pasteIndex + 1, pasteImageItem); label: pasteImageLabel,
} else { onPressed: () {
buttonItems.add(pasteImageItem); // Close the context menu first
ContextMenuController.removeAny();
// Use the captured imageData directly
_handleClipboardPasteWithData(imageData);
},
);
// Insert after Paste if found, otherwise add at the end
if (pasteIndex >= 0) {
buttonItems.insert(pasteIndex + 1, pasteImageItem);
} else {
buttonItems.add(pasteImageItem);
}
} }
} }
@@ -1621,7 +1634,7 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
.toList(), .toList(),
onContentInserted: _handleContentInserted, onContentInserted: _handleContentInserted,
), ),
// Custom context menu with "Paste Image" option for iOS // Custom context menu with "Paste Image" option
contextMenuBuilder: (context, editableTextState) { contextMenuBuilder: (context, editableTextState) {
return _buildContextMenu(context, editableTextState); return _buildContextMenu(context, editableTextState);
}, },