Skip to content

fix(mobile): accept Android clipboard images in composer - #4833

Closed
adityavardhansharma wants to merge 1 commit into
pingdotgg:mainfrom
adityavardhansharma:agent/android-clipboard-image-paste
Closed

fix(mobile): accept Android clipboard images in composer#4833
adityavardhansharma wants to merge 1 commit into
pingdotgg:mainfrom
adityavardhansharma:agent/android-clipboard-image-paste

Conversation

@adityavardhansharma

@adityavardhansharma adityavardhansharma commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

What Changed

Add Android rich-content handling to the native composer editor so images selected from the keyboard's clipboard history are attached to the draft.

Received images are copied into the composer's owned temporary directory and then passed through the existing attachment conversion, size validation, and cleanup path. Existing text paste behavior and the + image picker flow are unchanged.

Why

The Android editor already handled image URIs from the long-press Paste action, but keyboard clipboard-history images arrive through the IME commitContent/receive-content API instead of onTextContextMenuItem. Because the editor did not advertise or receive rich image content, Android reported those clipboard images as unsupported.

Using AndroidX receive-content support covers the IME path while keeping all attachment processing in the established composer pipeline.

Checklist

  • This PR is small and focused
  • I explained what changed and why

Validation

  • node scripts/mobile-native-static-check.ts
  • vp run typecheck from apps/mobile
  • git diff --check

Note

Accept Android clipboard images in the mobile composer editor

  • Adds a ViewCompat.setOnReceiveContentListener to SelectionAwareEditText in T3ComposerEditorView.kt that intercepts image content (JPEG, PNG, GIF, WebP) pasted from IMEs or drag-and-drop.
  • Received images are copied into a dedicated app cache subdirectory (t3-composer-paste) with UUID-based filenames, then passed to pasteImagesListener as file URIs.
  • Wraps the base InputConnection with InputConnectionCompat.createWrapper in onCreateInputConnection to enable rich content input compatibility on older Android versions.
📊 Macroscope summarized e86f3bf. 1 file reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f4589db7-ec5f-42c6-a716-9ca48dbc2568

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Jul 29, 2026
Comment on lines +463 to +471
ViewCompat.setOnReceiveContentListener(this, SUPPORTED_IMAGE_MIME_TYPES) { _, payload ->
val cachedImageUris = cacheReceivedImages(payload)
if (cachedImageUris.isEmpty()) {
payload
} else {
pasteImagesListener?.invoke(cachedImageUris)
null
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium t3composereditor/T3ComposerEditorView.kt:463

The receive-content listener returns null as soon as it caches at least one image, marking the entire payload as consumed. When a payload contains an image alongside text, unsupported items, or additional images that failed to cache, those remaining items are silently discarded instead of being returned to the platform for default handling. Consider partitioning the payload via payload.partition(...) and returning the unconsumed portion instead of null.

-      val cachedImageUris = cacheReceivedImages(payload)
-      if (cachedImageUris.isEmpty()) {
-        payload
-      } else {
-        pasteImagesListener?.invoke(cachedImageUris)
-        null
-      }
+      val (imagePayload, remainder) = payload.partition { item ->
+        val uri = item.uri
+        if (uri == null) return@partition false
+        val mimeType = context.contentResolver.getType(uri)?.lowercase()
+        mimeType != null && fileExtensionForImageMimeType(mimeType) != null
+      }
+      val cachedImageUris = cacheReceivedImages(imagePayload)
+      if (cachedImageUris.isNotEmpty()) {
+        pasteImagesListener?.invoke(cachedImageUris)
+      }
+      remainder
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/mobile/modules/t3-composer-editor/android/src/main/java/expo/modules/t3composereditor/T3ComposerEditorView.kt around lines 463-471:

The receive-content listener returns `null` as soon as it caches at least one image, marking the entire payload as consumed. When a payload contains an image alongside text, unsupported items, or additional images that failed to cache, those remaining items are silently discarded instead of being returned to the platform for default handling. Consider partitioning the payload via `payload.partition(...)` and returning the unconsumed portion instead of `null`.

@adityavardhansharma

Copy link
Copy Markdown
Contributor Author

Closing this draft to replace it with a corrected PR from current main.

@adityavardhansharma
adityavardhansharma deleted the agent/android-clipboard-image-paste branch July 29, 2026 13:54
@adityavardhansharma
adityavardhansharma restored the agent/android-clipboard-image-paste branch July 29, 2026 13:55
@adityavardhansharma
adityavardhansharma deleted the agent/android-clipboard-image-paste branch July 29, 2026 14:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant