Skip to content

Conversation

@divyanshu-patil
Copy link

@divyanshu-patil divyanshu-patil commented Dec 14, 2025

Proposed changes

  • created a custom fabric native component library react-native-typerich which fully supports new arch
  • uses TypeRichTextInput on android and TextInput on ios
  • added onPasteImageData event handler which opens ShareView to send images
  • doesn't break existing functionality and works exactly like the existing textinput
  • supports
    1. Gboard sticker pasting
    2. Gboard image pasting
    3. Gboard emoji kitchen image pasting
    4. context menu (long press) image pasting

Issue(s)

closes #1691
closes #178

How to test or reproduce

  1. open message composer on android
  2. navigate to gif section or sticker section
  3. try to paste

Screenshots

react-native-typerich.demo.mp4
image

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • Improvement (non-breaking change which improves a current function)
  • New feature (non-breaking change which adds functionality)
  • Documentation update (if none of the other choices apply)

Checklist

  • I have read the CONTRIBUTING doc
  • I have signed the CLA
  • I have added necessary documentation (if applicable)
  • Lint and unit tests pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works (if applicable)
  • Any dependent changes have been merged and published in downstream modules

Further comments

Future planning

  • add an use experimental message composer option in preferences menu to toggle between legacy composer and new Typerich composer
  • Real time markdown rendering that was limited previously by TextInput functionality
  • using spannables on android and attributed strings on ios for markdown rendering
  • rendering custom emojis directly into the composer
  • rendering the mentions chips and channel chips directly into the composer
    eg
image

i will update following checks once it supports all core features

  • user fast typing
  • context menu image paste
  • context menu text paste
  • markdown insertion using formatting toolbox
  • focus and blur
  • quote support
  • draft saving
  • edit message
  • Autocomplete for Mentions, Channels and Commands
  • working on iOS
  • tests for added features

Summary by CodeRabbit

  • New Features

    • Android: paste images directly into the composer via a new rich-text input and integrated share flow for pasted content.
  • Bug Fixes

    • More robust accessibility focus resolution for the composer.
    • Improved focus and selection handling and clearer paste error reporting.
  • Chores

    • Added runtime dependency to support the new rich-text input.

✏️ Tip: You can customize this high-level summary in your review settings.

@divyanshu-patil divyanshu-patil marked this pull request as draft December 14, 2025 13:05
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 14, 2025

Walkthrough

Adds Android clipboard image-paste support by rendering a rich-text input on Android and implementing paste→validate→navigate-to-share flow; updates composer input ref typing and accessibility focus resolution to more robustly obtain the native host element.

Changes

Cohort / File(s) Summary
Message Composer Container
app/containers/MessageComposer/MessageComposer.tsx
Changed composerInputRef typing to useRef<any>(null) and updated accessibilityFocusOnInput to resolve the host element via composerInputRef.current, call getNativeRef() if present, fallback to the input, then call findNodeHandle.
Composer Input Component (Android paste + selection/focus handling)
app/containers/MessageComposer/components/ComposerInput.tsx
Added Android-specific TypeRichTextInput rendering with onPasteImageData; implemented handleOnImagePaste to build a file object, validate with canUploadFile (permission, allow list, max size), navigate to ShareView for valid uploads, show Alert on errors; added startShareView/finishShareView, refined focus/blur/selection handlers, Android setValue vs non-Android setNativeProps behavior, and paste-related imports (Platform, rich-text types, Subscription, thread retrieval).
Runtime Dependencies
package.json
Added dependency: react-native-typerich ^1.1.1.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ComposerInput
    participant TypeRichTextInput
    participant PasteHandler
    participant CanUploadService
    participant ShareView
    participant Alert

    User->>ComposerInput: Paste image
    ComposerInput->>TypeRichTextInput: onPasteImageData(payload)
    TypeRichTextInput->>PasteHandler: deliver payload
    PasteHandler->>CanUploadService: canUploadFile(file, allowList, maxSize, perm)
    alt Upload Allowed
        PasteHandler->>ShareView: navigate(with file payload)
        ShareView-->>User: preview + confirm
    else Upload Denied
        PasteHandler->>Alert: show translated error message
        Alert-->>User: display error
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I found a shiny paste and gave it a hop,
Into the composer it landed with a plop,
I checked the bytes and measured the size,
Then bounced them off to share with bright eyes,
Android now hops and sends with a pop.

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly summarizes the main change: adding image pasting functionality to the message composer on Android.
Linked Issues check ✅ Passed The PR successfully implements image pasting (#1691) and GIF insertion (#178) by adding TypeRichTextInput for Android with onPasteImageData handler and proper file validation.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing Android image pasting: TypeRichTextInput integration, paste handling logic, file validation, and the necessary dependency. No unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

@divyanshu-patil divyanshu-patil marked this pull request as ready for review December 14, 2025 18:37
@divyanshu-patil divyanshu-patil changed the title wip: android image pasting feat: android image pasting Dec 14, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (4)
app/containers/MessageComposer/MessageComposer.tsx (1)

36-36: Loss of type safety with any type.

Changing from a specific type to any eliminates type checking and IntelliSense support. Consider using a union type or a more specific type that accommodates both TextInput and TypeRichTextInput refs.

For example:

-const composerInputRef = useRef<any>(null);
+const composerInputRef = useRef<TextInput | { getNativeRef?: () => any; focus: () => void; setValue?: (text: string) => void } | null>(null);

Or create a shared interface for both input components.

app/containers/MessageComposer/components/ComposerInput.tsx (2)

420-425: Avoid type assertion with as any.

Using as any bypasses type checking. Consider defining a proper interface for the file object or using the IShareAttachment type that canUploadFile expects.

+import type { IShareAttachment } from '../../../lib/methods/helpers';
+
 const file = {
 	filename: e.fileName,
 	size: e.fileSize,
 	mime: e.type,
 	path: e.uri
-} as any;
+} as IShareAttachment;

406-446: Consider adding error handling for navigation.

The Navigation.navigate call on line 434 doesn't handle potential navigation failures. Consider wrapping it in a try-catch block to handle edge cases gracefully.

 	if (canUploadResult.success) {
+		try {
 			Navigation.navigate('ShareView', {
 				room,
 				thread: thread || tmid,
 				attachments: [file],
 				action,
 				finishShareView,
 				startShareView
 			});
+		} catch (error) {
+			log(error);
+			handleError('error-navigation-failed');
+		}
 	} else {
package.json (1)

124-124: Consider the stability implications of pre-1.0 versions.

The react-native-typerich package at version 0.1.9 is the latest published version on npm with no known security vulnerabilities. However, as a pre-1.0 package, it may not have reached stable release status. Evaluate whether this early-stage version meets your project's stability requirements or if a more mature alternative should be considered.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between bddcf52 and 3a66e6a.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (3)
  • app/containers/MessageComposer/MessageComposer.tsx (2 hunks)
  • app/containers/MessageComposer/components/ComposerInput.tsx (9 hunks)
  • package.json (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
app/containers/MessageComposer/MessageComposer.tsx (1)
app/containers/UIKit/index.tsx (1)
  • input (169-183)
app/containers/MessageComposer/components/ComposerInput.tsx (4)
app/containers/MessageComposer/hooks/useCanUploadFile.ts (1)
  • useCanUploadFile (6-18)
app/lib/database/services/Subscription.ts (1)
  • getSubscriptionByRoomId (8-17)
app/lib/database/services/Thread.ts (1)
  • getThreadById (7-16)
app/lib/methods/helpers/media.ts (1)
  • canUploadFile (3-37)
🔇 Additional comments (2)
app/containers/MessageComposer/components/ComposerInput.tsx (2)

190-194: Verify platform-specific input update methods.

The Android path uses setValue() while the non-Android path uses setNativeProps({ text }). Ensure that both methods correctly update the input value and trigger the expected behavior in their respective components.

Based on learnings, verify that TypeRichTextInput.setValue() is the correct method for updating text programmatically on Android, and that it handles cursor positioning and selection as expected.


491-491: Selection change handler names are intentional for different components.

Line 491 uses onSelectionChange (React Native's TextInput) while line 466 uses onChangeSelection (TypeRichTextInput from react-native-typerich). The different prop names correspond to different event signatures: TextInput provides e.nativeEvent.selection, while TypeRichTextInput provides e with direct start and end properties. This is correct usage for the respective libraries and requires no changes.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (6)
app/containers/MessageComposer/components/ComposerInput.tsx (6)

81-81: Remove commented code.

The commented line // const isAndroid = false; should be removed as it appears to be debug code.

 const isAndroid = Platform.OS === 'android';
-// const isAndroid = false;

217-217: Remove debug console.log statement.

Debug logging should be removed before merging to production.

 const onChangeText: TextInputProps['onChangeText'] = text => {
 	textRef.current = text;
 	debouncedOnChangeText(text);
-	console.log(text);
 	setInput(text, undefined, true);
 };

225-231: Remove debug console.log statements.

Multiple debug console.log statements should be removed before merging.

 const onChangeSelection = (e: OnChangeSelectionEvent) => {
 	const { start, end } = e;
 	const selection = { start, end };
-	console.log('selection========', e);
 	selectionRef.current = selection;
-	console.log('sel', selection);
 };

411-411: Remove debug console.log statement.

Debug logging should be removed before merging.

 const handleOnPaste = async (e: onPasteImageEventData) => {
 	if (e.error) {
 		handleError(e.error.message);
 		return;
 	}
-	console.log(e);
 	if (!rid) return;

444-444: Remove debug console.log statement.

Debug logging should be removed before merging.

 	} else {
 		handleError(canUploadResult.error);
-		console.log('error block');
 	}

454-479: Remove debug text from placeholder.

Line 458 contains 'custom textinput ${placeholder}' which appears to be debug text. The placeholder should match the non-Android path.

 <TypeRichTextInput
 	style={[styles.textInput]}
 	color={colors.fontDefault}
-	placeholder={`custom textinput ${placeholder}`}
+	placeholder={placeholder}
 	placeholderTextColor={colors.fontAnnotation}
🧹 Nitpick comments (3)
app/containers/MessageComposer/components/ComposerInput.tsx (3)

233-253: Consider standardizing focus/blur handler usage.

The focus/blur logic is correctly extracted into handleFocus and handleBlur. However, the Android path (lines 467-468) directly uses these handlers, while the non-Android path (lines 492-493) uses the onFocus/onBlur wrappers. For consistency, consider using the same approach in both paths.

Apply this diff to use wrappers consistently:

-					onFocus={handleFocus}
-					onBlur={handleBlur}
+					onFocus={onFocus}
+					onBlur={onBlur}

425-425: Replace type assertion with proper interface.

The as any type assertion bypasses type safety. Consider defining a proper type or using the IShareAttachment interface directly.

-		} as any;
+		} as IShareAttachment;

Alternatively, import and use the correct type from the share attachment definitions.


463-463: Fix typo in comment.

Line 469 contains a typo: "behaiviour" should be "behaviour".

-		// underlineColorAndroid='transparent' // by default behaiviour
+		// underlineColorAndroid='transparent' // by default behaviour

Also applies to: 469-469

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3a66e6a and ff68f0b.

📒 Files selected for processing (1)
  • app/containers/MessageComposer/components/ComposerInput.tsx (9 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
app/containers/MessageComposer/components/ComposerInput.tsx (4)
app/containers/MessageComposer/hooks/useCanUploadFile.ts (1)
  • useCanUploadFile (6-18)
app/lib/database/services/Subscription.ts (1)
  • getSubscriptionByRoomId (8-17)
app/lib/database/services/Thread.ts (1)
  • getThreadById (7-16)
app/lib/methods/helpers/media.ts (1)
  • canUploadFile (3-37)
🔇 Additional comments (6)
app/containers/MessageComposer/components/ComposerInput.tsx (6)

2-2: LGTM! Imports support the new Android paste functionality.

The new imports are all used appropriately in the implementation: Alert for error dialogs, TypeRichTextInput for Android-specific input handling, canUploadFile for permission validation, and database services for retrieving room/thread context during paste operations.

Also applies to: 6-6, 8-8, 20-20, 47-48


75-80: LGTM! Permission checks properly initialized.

The permission flags and settings are correctly retrieved and will be used in the paste handler to validate file uploads.


190-194: LGTM! Platform-specific input update methods handled correctly.

The conditional logic appropriately uses setValue for Android's TypeRichTextInput and setNativeProps for the standard TextInput, accounting for the different APIs of these components.


448-450: LGTM! Error handling with translated messages.

The error handler correctly displays translated error messages via Alert, with a fallback for untranslated errors.


480-502: LGTM! TextInput configuration for non-Android platforms.

The standard TextInput is correctly configured with appropriate handlers and props for iOS and other platforms. The different prop names (onSelectionChange vs onChangeSelection) are correct as they match each component's API.


517-518: LGTM! Style property ordering.

Minor reordering of fontSize placement in the style definition. No functional impact.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
app/containers/MessageComposer/components/ComposerInput.tsx (1)

460-509: Consider extracting shared props to reduce duplication.

The Android and non-Android render paths duplicate many props (placeholder, colors, multiline, etc.). While the differences in event handlers are intentional, you could extract the common props into a shared object to improve maintainability.

Example refactor:

const commonProps = {
	placeholderTextColor: colors.fontAnnotation,
	defaultValue: '',
	multiline: true,
	...(autocompleteType ? { autoComplete: 'off', autoCorrect: false, autoCapitalize: 'none' } : {}),
	keyboardAppearance: theme === 'light' ? 'light' : 'dark',
	testID: `message-composer-input${tmid ? '-thread' : sharing ? '-share' : ''}`,
	onChangeText,
	onTouchStart
};

Then spread commonProps into both branches and add platform-specific props separately.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ff68f0b and 855ee28.

📒 Files selected for processing (1)
  • app/containers/MessageComposer/components/ComposerInput.tsx (8 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
app/containers/MessageComposer/components/ComposerInput.tsx (4)
app/containers/MessageComposer/hooks/useCanUploadFile.ts (1)
  • useCanUploadFile (6-18)
app/lib/database/services/Subscription.ts (1)
  • getSubscriptionByRoomId (8-17)
app/lib/database/services/Thread.ts (1)
  • getThreadById (7-16)
app/lib/methods/helpers/media.ts (1)
  • canUploadFile (3-37)
🔇 Additional comments (3)
app/containers/MessageComposer/components/ComposerInput.tsx (3)

75-79: LGTM!

The upload permission and file constraints are correctly retrieved using the custom hook and Redux selectors.


233-253: LGTM!

The focus/blur handler wrappers allow for platform-specific event handling. The Android TypeRichTextInput uses handleFocus/handleBlur directly, while the standard TextInput uses the wrapped onFocus/onBlur handlers.


190-194: Verify setValue method signature in react-native-typerich package.

The Android path uses inputRef.current?.setValue(text) which is a TypeRichTextInput-specific API (version 0.1.9). The package exists on npm, and the platform-specific branching is correct—TypeRichTextInput is only rendered on Android, while the non-Android path uses standard React Native TextInput with setNativeProps. However, confirm the exact method signature and parameters for setValue in the react-native-typerich documentation or package source.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (6)
app/containers/MessageComposer/components/ComposerInput.tsx (6)

81-82: Remove commented debug code.

The commented line at line 82 should be removed as it's leftover debug code.

Apply this diff:

 const isAndroid = Platform.OS === 'android';
-// const isAndroid = false;

218-218: Remove debug console.log statement.

Debug logging should be removed before merging to production.

Apply this diff:

 const onChangeText: TextInputProps['onChangeText'] = text => {
 	textRef.current = text;
 	debouncedOnChangeText(text);
-	console.log(text);
 	setInput(text, undefined, true);
 };

226-232: Remove debug console.log statements.

Multiple debug console.log statements should be removed before merging.

Apply this diff:

 const onChangeSelection = (e: OnChangeSelectionEvent) => {
 	const { start, end } = e;
 	const selection = { start, end };
-	console.log('selection========', e);
 	selectionRef.current = selection;
-	console.log('sel', selection);
 };

412-412: Remove debug console.log statement.

Debug logging should be removed before merging to production.

Apply this diff:

 const handleOnImagePaste = async (e: onPasteImageEventData) => {
 	if (e.error) {
 		handleError(e.error.message);
 		return;
 	}
-	console.log(e);
 	if (!rid) return;

451-451: Remove debug console.log statement.

Debug logging should be removed before merging to production.

Apply this diff:

 	} else {
 		handleError(canUploadResult.error);
-		console.log('error block');
 	}

465-465: Remove debug text from placeholder.

The placeholder contains debug text 'custom textinput ${placeholder}' which should be replaced with just {placeholder} to match the non-Android path.

Apply this diff:

 <TypeRichTextInput
 	style={[styles.textInput]}
 	color={colors.fontDefault}
-	placeholder={`custom textinput ${placeholder}`}
+	placeholder={placeholder}
 	placeholderTextColor={colors.fontAnnotation}
🧹 Nitpick comments (1)
app/containers/MessageComposer/components/ComposerInput.tsx (1)

455-457: Improve error message fallback handling.

When error is undefined, the Alert will display "undefined" as the message. Consider providing a default error message.

Apply this diff to improve the fallback:

 const handleError = (error?: string) => {
-	Alert.alert(I18n.t('Error_uploading'), error && I18n.isTranslated(error) ? I18n.t(error) : error);
+	Alert.alert(
+		I18n.t('Error_uploading'), 
+		error && I18n.isTranslated(error) ? I18n.t(error) : (error || I18n.t('An_error_occurred'))
+	);
 };
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 855ee28 and b9cfb96.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (2)
  • app/containers/MessageComposer/components/ComposerInput.tsx (8 hunks)
  • package.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json
🧰 Additional context used
🧬 Code graph analysis (1)
app/containers/MessageComposer/components/ComposerInput.tsx (5)
app/containers/MessageComposer/hooks/useCanUploadFile.ts (1)
  • useCanUploadFile (6-18)
app/lib/database/services/Subscription.ts (1)
  • getSubscriptionByRoomId (8-17)
app/lib/database/services/Thread.ts (1)
  • getThreadById (7-16)
app/definitions/IAttachment.ts (1)
  • IShareAttachment (78-92)
app/lib/methods/helpers/media.ts (1)
  • canUploadFile (3-37)
🔇 Additional comments (3)
app/containers/MessageComposer/components/ComposerInput.tsx (3)

191-195: LGTM - Platform-specific input methods handled correctly.

The code appropriately uses setValue for the Android TypeRichTextInput and setNativeProps for the standard TextInput, with proper optional chaining for safety.


234-254: LGTM - Event handlers properly structured.

The separation between core handlers (handleFocus, handleBlur) and typed wrappers (onFocus, onBlur) is appropriate. The Android path calls core handlers directly while the non-Android TextInput path uses the typed wrappers, accommodating different component APIs.


470-470: Verify blurOnSubmit behavior for TypeRichTextInput.

The Android path has blurOnSubmit commented out (line 470), while the non-Android TextInput explicitly sets blurOnSubmit={false} (line 493). Inspect the TypeRichTextInput component implementation to confirm whether it supports the blurOnSubmit prop, what its default behavior is, and why it differs from the standard TextInput approach.

if (canUploadResult.success) {
Navigation.navigate('ShareView', {
room,
thread: thread || tmid,
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, find ShareView component definition
fd -e tsx -e ts | xargs rg -l "ShareView" | head -20

Repository: RocketChat/Rocket.Chat.ReactNative

Length of output: 539


🏁 Script executed:

# Look for ShareView component and its type definition
rg "export.*ShareView|interface.*ShareView|type.*ShareView" -A 10

Repository: RocketChat/Rocket.Chat.ReactNative

Length of output: 1423


🏁 Script executed:

# Check the ComposerInput file to understand the types of thread and tmid variables
cat -n app/containers/MessageComposer/components/ComposerInput.tsx | sed -n '430,460p'

Repository: RocketChat/Rocket.Chat.ReactNative

Length of output: 960


🏁 Script executed:

# Get the function signature and variable declarations in ComposerInput.tsx
cat -n app/containers/MessageComposer/components/ComposerInput.tsx | sed -n '1,100p'

Repository: RocketChat/Rocket.Chat.ReactNative

Length of output: 5708


🏁 Script executed:

# Search for thread and tmid variable declarations and their types
rg "thread|tmid" app/containers/MessageComposer/components/ComposerInput.tsx -B 3 -A 1 | head -80

Repository: RocketChat/Rocket.Chat.ReactNative

Length of output: 2336


🏁 Script executed:

# Check the exact function containing line 443
ast-grep --pattern $'const $_ = ($_) => {
  $$$
  thread: thread || tmid
  $$$
}'

Repository: RocketChat/Rocket.Chat.ReactNative

Length of output: 60


🏁 Script executed:

# Find getThreadById definition and its return type
rg "export.*getThreadById|function getThreadById" -A 5

Repository: RocketChat/Rocket.Chat.ReactNative

Length of output: 498


🏁 Script executed:

# Check useRoomContext return type
rg "useRoomContext" app/views/RoomView/context.tsx -A 30 | head -80

Repository: RocketChat/Rocket.Chat.ReactNative

Length of output: 148


🏁 Script executed:

# Look for the complete function context around line 443 to see the full picture
cat -n app/containers/MessageComposer/components/ComposerInput.tsx | sed -n '410,450p'

Repository: RocketChat/Rocket.Chat.ReactNative

Length of output: 1140


🏁 Script executed:

# Find RoomContext definition
fd -type f -name "*.tsx" -o -name "*.ts" | xargs rg -l "useRoomContext" | grep -i context

Repository: RocketChat/Rocket.Chat.ReactNative

Length of output: 295


🏁 Script executed:

# Check the collection find() return type and thread model type
rg "threadCollection.find|TThreadModel|IThread" app/lib/database/services/Thread.ts -A 3 -B 3

Repository: RocketChat/Rocket.Chat.ReactNative

Length of output: 261


🏁 Script executed:

# Look for the context definition
fd -type f \( -name "*context*" \) | grep -i room

Repository: RocketChat/Rocket.Chat.ReactNative

Length of output: 248


🏁 Script executed:

# Read RoomContext type definition
cat -n app/views/RoomView/context.ts | head -150

Repository: RocketChat/Rocket.Chat.ReactNative

Length of output: 1099


🏁 Script executed:

# Look for the context provider and useRoomContext hook definition
rg "useRoomContext|export.*RoomContext" app/views/RoomView/context.ts -A 15 | head -100

Repository: RocketChat/Rocket.Chat.ReactNative

Length of output: 797


🏁 Script executed:

// Instead of:
thread: thread || tmid

// Use:
thread: thread || tmid || ''
// or guard against undefined earlier

Repository: RocketChat/Rocket.Chat.ReactNative

Length of output: 410


Remove the type union issue by ensuring a non-undefined value is always passed to ShareView.

The code passes thread: thread || tmid to ShareView, but tmid is typed as string | undefined in the RoomContext, and getThreadById() returns TThreadModel | null. This means the expression can evaluate to undefined when both thread and tmid are falsy. However, ShareView's type definition expects thread: TThreadModel | string (excluding undefined).

To fix this, ensure a valid value is always passed—either by providing a fallback value (e.g., thread: thread || tmid || '') or by adding a guard condition to prevent navigation when neither value is available.

🤖 Prompt for AI Agents
In app/containers/MessageComposer/components/ComposerInput.tsx around line 443,
the prop `thread: thread || tmid` can evaluate to undefined because tmid is
typed string | undefined and thread may be null, violating ShareView's expected
TThreadModel | string; fix by ensuring a non-undefined value is passed — either
provide a safe fallback like `thread || tmid || ''` or add a guard that prevents
calling/navigating to ShareView when both thread and tmid are falsy so ShareView
always receives a valid string or TThreadModel.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b9cfb96 and 9719e2d.

📒 Files selected for processing (1)
  • app/containers/MessageComposer/components/ComposerInput.tsx (8 hunks)
🔇 Additional comments (10)
app/containers/MessageComposer/components/ComposerInput.tsx (10)

2-2: LGTM! Imports support the new Android paste flow.

All new imports (Platform, Alert, TypeRichTextInput, paste event types, upload validation helpers, and data retrieval functions) are properly used in the Android image-paste implementation.

Also applies to: 6-6, 8-8, 20-20, 47-49


76-81: LGTM! Upload settings properly initialized.

The upload permission check and file size/type constraints are correctly retrieved from the room context and settings, and the platform check appropriately gates Android-specific behavior.


190-194: LGTM! Input value updates correctly handle both input types.

The conditional correctly uses setValue for Android's TypeRichTextInput and setNativeProps for the standard TextInput on other platforms, respecting each component's API.


214-218: LGTM! Draft message handling is correct.

The onChangeText handler properly passes forceUpdateDraftMessage: true to ensure draft persistence is updated when the user types, addressing the previous review feedback.


224-228: LGTM! Selection tracking handles TypeRichTextInput events correctly.

The onChangeSelection handler correctly extracts start and end directly from the TypeRichTextInput event (rather than from nativeEvent.selection as in standard TextInput), properly adapting to the library's event structure.


230-250: LGTM! Focus/blur handling correctly adapts to different event signatures.

The layered handlers (handleFocus/handleBlur without parameters, onFocus/onBlur with parameters) properly accommodate TypeRichTextInput's no-argument callbacks (line 468 comment) while maintaining compatibility with TextInput's event-based callbacks. The iOS back-swipe check in handleBlur is preserved.


396-401: LGTM! Share view helpers are correctly implemented.

The startShareView and finishShareView helpers provide clean callbacks for initializing and finalizing the share flow, properly integrating with the existing selectedMessages and setQuotesAndText context.


449-451: LGTM! Error handling is user-friendly.

The handleError helper properly displays localized error messages via Alert, checking whether the error string is a translation key and falling back to the raw message when needed.


454-502: LGTM! Platform-specific rendering correctly implements image paste for Android.

The conditional rendering properly branches on isAndroid to render:

  • Android: TypeRichTextInput with onPasteImageData={handleOnImagePaste} (line 477) to enable image paste, using handleFocus/handleBlur directly (no event parameters), and onChangeSelection for TypeRichTextInput's event structure
  • Non-Android: Standard TextInput with onFocus/onBlur wrappers (accepting event parameters) and onSelectionChange for React Native's event structure

Both paths share common props (placeholder, colors, testID, keyboard appearance) while correctly adapting event handlers to each component's API as documented in the line 468 comment.


516-517: LGTM! Style reordering has no functional impact.

Swapping lineHeight and fontSize order is a cosmetic change with no effect on rendering behavior.

@divyanshu-patil divyanshu-patil marked this pull request as draft December 15, 2025 12:59
@divyanshu-patil
Copy link
Author

converting to draft as app is crashing on opening on ios

@divyanshu-patil divyanshu-patil marked this pull request as ready for review December 15, 2025 14:46
@divyanshu-patil
Copy link
Author

divyanshu-patil commented Dec 15, 2025

IOS app crashing issue is fixed in v0.1.11 of react-native-typerich

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9719e2d and bb91f3c.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (1)
  • package.json (1 hunks)

@divyanshu-patil divyanshu-patil changed the title feat: android image pasting feat: android image pasting in message composer Dec 15, 2025
@divyanshu-patil divyanshu-patil changed the title feat: android image pasting in message composer feat(Android): image pasting in message composer Dec 17, 2025
@divyanshu-patil divyanshu-patil marked this pull request as draft December 19, 2025 04:38
@divyanshu-patil
Copy link
Author

converting to draft as lib is in beta stage
once the lib gets stable i will mark as ready for review

@divyanshu-patil divyanshu-patil marked this pull request as ready for review December 23, 2025 20:34
@divyanshu-patil
Copy link
Author

lib is stable and tested with v1.1.1 and changes can be safely merged

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
app/containers/MessageComposer/components/ComposerInput.tsx (1)

405-449: Fix the thread parameter type violation.

Past reviews flagged this as critical and marked it as addressed in commit 855ee28, but the code at line 440 still shows the unfixed issue.

Problem: The expression thread || tmid can evaluate to undefined:

  • When pasting in the main room (not in a thread), tmid is undefined
  • thread remains undefined because the conditional block at lines 420-422 doesn't execute
  • getThreadById returns TThreadModel | null, and tmid is typed string | undefined
  • ShareView expects thread: TThreadModel | string, excluding undefined

Impact: This type contract violation can cause runtime errors when ShareView attempts to access thread properties.

🔎 Recommended fix

Apply one of these solutions:

Solution 1 (simplest): Provide a fallback empty string:

 Navigation.navigate('ShareView', {
 	room,
-	thread: thread || tmid,
+	thread: thread || tmid || '',
 	attachments: [file],
 	action,
 	finishShareView,
 	startShareView
 });

Solution 2: Add a guard condition if ShareView cannot handle empty strings for the main room case:

+	// When pasting in main room (not thread), thread param may be undefined
+	if (!thread && !tmid) {
+		// Handle main room paste - consider if thread should be optional in ShareView
+		// or if empty string is acceptable
+	}
+
 	Navigation.navigate('ShareView', {
 		room,
 		thread: thread || tmid,
 		attachments: [file],
 		action,
 		finishShareView,
 		startShareView
 	});
🧹 Nitpick comments (1)
app/containers/MessageComposer/components/ComposerInput.tsx (1)

158-159: Address or remove the TODO comment.

The TODO comment at line 158 (// todo mention command here) appears to be leftover from development. If additional logic is needed for the mention command, please implement it or create a tracking issue. Otherwise, remove the comment.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between bf0781b and 57b6564.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (2)
  • app/containers/MessageComposer/components/ComposerInput.tsx
  • package.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json
🧰 Additional context used
🧬 Code graph analysis (1)
app/containers/MessageComposer/components/ComposerInput.tsx (5)
app/containers/MessageComposer/hooks/useCanUploadFile.ts (1)
  • useCanUploadFile (6-18)
app/lib/database/services/Subscription.ts (1)
  • getSubscriptionByRoomId (8-17)
app/lib/database/services/Thread.ts (1)
  • getThreadById (7-16)
app/definitions/IAttachment.ts (1)
  • IShareAttachment (78-92)
app/lib/methods/helpers/media.ts (1)
  • canUploadFile (3-37)
🔇 Additional comments (4)
app/containers/MessageComposer/components/ComposerInput.tsx (4)

398-403: LGTM!

The ShareView helper functions correctly integrate the paste flow with the existing share functionality.


451-453: LGTM!

The error handler properly integrates with the I18n system and provides good user feedback.


192-196: The APIs used (setText, onChangeSelection, onPasteImageData) are properly imported with TypeScript types from react-native-typerich@^1.1.1, which is a stable release version. All methods are correctly typed and safely guarded with optional chaining. No API compatibility verification is needed.


6-6: The version number in this review is incorrect. The library react-native-typerich is specified as version ^1.1.1 in package.json, not 0.1.11+. Additionally, the handleOnImagePaste implementation already includes comprehensive error handling: it checks for e.error, validates rid and room existence, and uses canUploadFile validation with error callbacks. The suggested verification concerns about incomplete error handling are unfounded based on the actual code implementation.

Likely an incorrect or invalid review comment.

const text = textRef.current;
const newText = `${text.substr(0, start)}@${text.substr(start, end - start)}${text.substr(end)}`;
setInput(newText, { start: start + 1, end: start === end ? start + 1 : end + 1 });
// todo mention command here
Copy link
Author

Choose a reason for hiding this comment

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

this comment is marked for future PR's to include live markdown directly inside the TextInput itself

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[IMPROVEMENT] Upload images from clipboard Gif insert from keyboard

1 participant