Skip to content

Conversation

@dev-amirzubair
Copy link

Turbo modules fixed
will work for both new and old architecture
also both Android and iOS

@safaiyeh
Copy link
Member

@greptile review

@safaiyeh
Copy link
Member

@dev-amirzubair thank you for the fixes! Can you rebase and address (if any) comments from greptile

@greptile-apps
Copy link

greptile-apps bot commented Dec 27, 2025

Greptile Summary

  • Implements comprehensive dual architecture support for React Native's new TurboModules/Fabric alongside legacy bridge architecture, enabling the library to work with both modern and legacy React Native apps
  • Refactors Android and iOS native module implementations with architecture-specific source directories (android/src/newarch/ and android/src/oldarch/), lazy initialization patterns, and enhanced error handling
  • Modernizes documentation, example components, and troubleshooting guides while adding new transcription features with timing metadata and improved speech recognition configuration options

Important Files Changed

Filename Overview
src/index.ts Major refactoring implementing TurboModule detection with fallback to NativeModules, platform-specific event emitter setup, and complex dual architecture initialization logic
android/src/main/java/com/wenkesj/voice/Voice.kt Extensive changes adding 40+ debug log statements, hardcoded locale mappings, backward compatibility handling, and enhanced error handling that may impact production performance
src/NativeVoiceAndroid.ts Breaking change replacing getEnforcing() with get() method that returns nullable instead of throwing errors, requiring null checks in consuming code
src/NativeVoiceIOS.ts Updates iOS TurboModule interface with file transcription support and breaking change from getEnforcing() to get() method affecting error handling behavior
android/gradle.properties Breaking changes updating minimum SDK from 21 to 24 (dropping Android 5.0-6.0 support) and upgrading all build tool versions for new architecture compatibility

Confidence score: 2/5

  • This PR requires careful review due to multiple breaking changes, complex architecture detection logic, and potential production issues with extensive debug logging
  • Score lowered due to breaking changes in TurboModule error handling (getEnforcing to get), minimum SDK requirements, excessive debug logging in Voice.kt, and complex dual architecture initialization that could fail silently
  • Pay close attention to src/index.ts for architecture detection logic, android/src/main/java/com/wenkesj/voice/Voice.kt for production logging concerns, and the TurboModule interface files for breaking API changes

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Additional Comments (7)

  1. android/src/oldarch/VoiceSpec.kt, line 18 (link)

    style: consider using UnsupportedOperationException instead of NotImplementedError for better Java interoperability

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  2. react-native-voice.podspec, line 19 (link)

    logic: Repository URL changed from official react-native-voice organization to personal fork. This should be reverted before merging to main unless this is intentional for development. Is this repository URL change intended to be permanent, or should this point back to the official react-native-voice repository?

  3. package.json, line 67 (link)

    logic: dev-sync script references old package path @react-native-voice/voice instead of new package name @dev-amirzubair/react-native-voice

  4. example/src/VoiceTest.tsx, line 88-96 (link)

    style: All callback functions in dependency array will cause useEffect to re-run whenever any callback changes, potentially causing Voice event handlers to be re-registered unnecessarily. Would it be better to use useRef for stable callback references or remove some dependencies?

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  5. example/src/VoiceTest.tsx, line 72 (link)

    style: Parameter e should be typed instead of using any

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  6. src/index.ts, line 271 (link)

    logic: cancelTranscription() calls Voice.cancelSpeech() but should call Voice.cancelTranscription()

  7. src/index.ts, line 189-194 (link)

    style: startTranscription() uses old manual listener setup while start() uses new _setupListeners() approach, creating inconsistency

19 files reviewed, 7 comments

Edit Code Review Agent Settings | Greptile

@dev-amirzubair
Copy link
Author

@safaiyeh, I have resolved the conflicts and addressed the comments.

@pranabkumarbehera
Copy link

@dev-amirzubair After installing your plugin what's need to change , please kindly tell me

@pranabkumarbehera
Copy link

@dev-amirzubair Thanks bro. Everything working fine in 0.82.0 version ..Great

@dprajapati1179
Copy link

dprajapati1179 commented Dec 31, 2025

@dev-amirzubair @safaiyeh Any confirmations when we ca expect the new version update for the same ?

also is the known issue of "required condition is false: IsFormatSampleRateAndChannelCountValid(format)" has been addressed in this PR or not ?

#388

@dprajapati1179
Copy link

@greptile review

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Additional Comments (6)

  1. src/VoiceModuleTypes.ts, line 53 (link)

    logic: Breaking change: segments field changed from string[] to TranscriptionSegment[]. This will break existing code that expects string arrays despite the backward compatibility claim. Should this be a major version bump since it's a breaking change to the segments API?

  2. src/VoiceModuleTypes.ts, line 47-49 (link)

    logic: Documentation incorrectly claims backward compatibility when the segments field type has fundamentally changed

  3. example/src/VoiceTest.tsx, line 72-74 (link)

    syntax: setPitch receives potentially undefined value from e.value, causing type mismatch with useState<string>

  4. README.md, line 18 (link)

    logic: Package name mismatch: shows @react-native-voice/voice but package.json indicates this fork is @dev-amirzubair/react-native-voice

    Should this installation command reference your fork package name instead?

  5. README.md, line 175 (link)

    logic: Plugin reference uses wrong package name - should match your fork name from package.json

  6. src/index.ts, line 309-359 (link)

    style: Calling _setupListeners() on every event setter creates performance overhead - listeners are removed and re-added repeatedly even when unchanged. Would it be more efficient to track which events have changed and only update listeners when necessary?

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

18 files reviewed, 6 comments

Edit Code Review Agent Settings | Greptile

@dev-amirzubair
Copy link
Author

@greptile review

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Additional Comments (7)

  1. src/VoiceModuleTypes.ts, line 58 (link)

    logic: This is a breaking change despite the documentation claiming otherwise. Changing segments from string[] to TranscriptionSegment[] will cause TypeScript errors and runtime failures for existing code that expects string arrays. Was this intended as a breaking change, or should a new field be added instead to maintain true backward compatibility?

  2. android/src/newarch/VoiceSpec.kt, line 54 (link)

    style: Inconsistent indentation - should align with other override methods

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  3. src/NativeVoiceAndroid.ts, line 6-8 (link)

    logic: Breaking change: EXTRA_MAX_RESULTS changed from string to number and EXTRA_PARTIAL_RESULTS from string to boolean. Existing code passing strings will fail at runtime.

  4. package.json, line 41 (link)

    logic: The version range allows for React 16, 17, or 18 but the React peer dep requires 18+ - this creates a potential conflict

  5. src/index.ts, line 125-127 (link)

    logic: Logic error: !this._loaded && !this._listeners should be || not && - if either condition is false, the method should continue. Should this check if either _loaded is false OR _listeners is empty, rather than both conditions being false?

  6. src/index.ts, line 140-142 (link)

    logic: Same logical issue as destroy() method - should use || instead of &&

  7. src/index.ts

    logic: Same logical issue repeated in stop() - early return condition should use ||

19 files reviewed, 7 comments

Edit Code Review Agent Settings | Greptile

…e safety

- Fix TranscriptionResultsEvent segments to support both string[] and TranscriptionSegment[] for backward compatibility
- Fix SpeechOptions to support both legacy string and new number/boolean types
- Fix Android Kotlin code to handle both string and number/boolean formats
- Fix logic errors in stopTranscription(), cancel(), and cancelTranscription() methods (use || instead of &&)
- Fix react-is version range to match React 18+ requirement (>=18.0.0)
- Fix indentation in VoiceSpec.kt
- Update documentation to clarify breaking changes
@dev-amirzubair
Copy link
Author

@greptile review

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Additional Comments (5)

  1. src/VoiceModuleTypes.ts, line 63 (link)

    style: The union type string[]| TranscriptionSegment[] creates type ambiguity for consumers. Consider using a discriminated union with a format field or providing separate event types to distinguish between legacy and new formats. How will consumers differentiate between the two formats at runtime to safely access the data?

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  2. example/src/VoiceTestFuncComp.tsx, line 124 (link)

    style: Services state is not cleared in _clearState() function - consider adding setServices([]) to maintain consistency with other state clearing. Should the services list be cleared when clearing other state, or should it persist across speech recognition sessions?

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  3. src/index.ts, line 33 (link)

    style: Variable isBridgelessEnabled is declared but never used in the code

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  4. src/index.ts, line 120 (link)

    style: Using JSON.parse(JSON.stringify([])) to create empty array is unnecessarily complex - use [] instead

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  5. src/index.ts, line 150 (link)

    style: Inconsistent array clearing: line 120 uses JSON.parse(JSON.stringify([])) while line 150 also uses it - consider using [] for consistency and performance

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

19 files reviewed, 5 comments

Edit Code Review Agent Settings | Greptile

- Add isTranscriptionSegmentArray() type guard to help consumers differentiate between string[] and TranscriptionSegment[] formats
- Update TranscriptionResultsEvent documentation to clarify runtime vs TypeScript types
- Remove unused isBridgelessEnabled variable
- Simplify array initialization (replace JSON.parse(JSON.stringify([])) with [])
- Fix state clearing consistency in VoiceTestFuncComp example
@dev-amirzubair
Copy link
Author

@greptile review

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Additional Comments (2)

  1. src/VoiceModuleTypes.ts, line 102-104 (link)

    logic: Empty array check returns false for new format - this could be unexpected behavior since empty TranscriptionSegment[] is still the new format. Should an empty segments array be considered the new TranscriptionSegment format rather than returning false?

  2. src/NativeVoiceAndroid.ts, line 50 (link)

    logic: Using getEnforcing() here but the iOS implementation switched to get() with null checks - this inconsistency could cause issues if the Android module isn't available. Should this also use get() with proper null handling like the iOS implementation?

19 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

- Fix isTranscriptionSegmentArray() to return true for empty arrays (new format)
- Change Android TurboModuleRegistry.getEnforcing() to get() for consistency with iOS
- Add graceful fallback handling for Android module availability
@dev-amirzubair
Copy link
Author

@greptile review

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Additional Comments (5)

  1. src/NativeVoiceIOS.ts, line 30 (link)

    logic: Breaking change: switched from getEnforcing() to get() which returns nullable instead of throwing. Consumer code must now handle null cases. Has the consuming code been updated to handle the nullable return value?

  2. src/NativeVoiceAndroid.ts, line 50-51 (link)

    logic: Breaking change: switching from getEnforcing() to get() changes error handling behavior - the module can now return null instead of throwing, requiring null checks in consuming code. How is null handling implemented in the consuming code to prevent runtime errors when the TurboModule isn't available?

  3. src/index.ts, line 122 (link)

    logic: logic changed from !this._loaded && !this._listeners to !this._loaded || this._listeners.length === 0 - this may prevent operations when only one condition is false. Should this method return early if _loaded is true but there are no listeners, or vice versa?

  4. src/VoiceModuleTypes.ts, line 107-108 (link)

    logic: Empty array assumption may be incorrect - if the native implementation can legitimately return an empty string array, this logic would incorrectly identify it as TranscriptionSegment[] format. Can the native iOS implementation ever return an empty string array, or is it guaranteed that empty arrays will always be in the new TranscriptionSegment format?

  5. src/VoiceModuleTypes.ts, line 112 (link)

    logic: Type guard relies only on presence of 'transcription' property - objects with this property but different structure could incorrectly pass the check

19 files reviewed, 5 comments

Edit Code Review Agent Settings | Greptile

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants