Expose completion callback for audio recording#6290
Conversation
Co-Authored-By: Claude <noreply@anthropic.com>
PR checklist ✅All required conditions are satisfied:
🎉 Great job! This PR is ready for review. |
|
SDK Size Comparison 📏
|
WalkthroughThe Changes
Sequence Diagram(s)sequenceDiagram
participant VM as ViewModel
participant Ctrl as MessageComposerController
participant Audio as AudioRecordingController
participant CB as Callback Handler
alt With Completion Callback
VM->>Ctrl: completeRecording(onComplete)
Ctrl->>Ctrl: Launch Coroutine
Ctrl->>Audio: completeRecordingSync()
Audio-->>Ctrl: Attachment Result
Ctrl->>Ctrl: Append to selectedAttachments
Ctrl->>CB: onComplete(Result<Attachment>)
CB-->>CB: Handle Result
else Without Callback
VM->>Ctrl: completeRecording(null)
Ctrl->>Audio: completeRecording()
Audio-->>Ctrl: Async completion
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/viewmodel/messages/MessageComposerViewModel.kt (1)
277-278: Consider adding KDoc for consistency.Other public methods in this ViewModel (e.g.,
setMessageInput,sendMessage) include KDoc. Adding documentation forcompleteRecordingwould maintain consistency and help SDK consumers understand the callback behavior.📝 Suggested KDoc
+ /** + * Completes audio recording and updates the composer attachments. + * + * `@param` onComplete Optional callback invoked with the result of the recording. + * On success, the recorded [Attachment] is added to [selectedAttachments] before + * the callback is invoked. + */ public fun completeRecording(onComplete: ((Result<Attachment>) -> Unit)? = null): Unit = messageComposerController.completeRecording(onComplete)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/viewmodel/messages/MessageComposerViewModel.kt` around lines 277 - 278, Add a KDoc comment for the public function MessageComposerViewModel.completeRecording explaining its purpose (finalizes the current audio recording), the optional onComplete callback signature ((Result<Attachment>) -> Unit) and what values the Result conveys (success contains the created Attachment, failure contains the error), and any threading/ordering expectations; place the KDoc immediately above the completeRecording method (which delegates to messageComposerController.completeRecording) to match the style and detail used for other public methods like setMessageInput and sendMessage.stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/MessageComposerController.kt (1)
925-930: Consider documenting callback execution context.The KDoc describes what happens when
onCompleteis provided, but it would be helpful to document that the callback is invoked on the main/immediate dispatcher thread. This helps callers understand thread safety when performing UI updates in the callback.📝 Suggested KDoc enhancement
* `@param` onComplete Optional callback invoked with the result of the recording once the recording has been * finalized. On success, the recorded [Attachment] is added to [selectedAttachments] before the callback - * is invoked, so callers can safely build and send a message using the received attachment. + * is invoked, so callers can safely build and send a message using the received attachment. + * The callback is invoked on the main thread.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/MessageComposerController.kt` around lines 925 - 930, Update the KDoc for MessageComposerController's audio-completion method to state the execution context of the onComplete callback: document that the onComplete callback (invoked after the recorded Attachment is added to MessageComposerState.attachments/selectedAttachments) is executed on the main (UI) dispatcher / immediate coroutine context so callers can safely perform UI updates. Mention the dispatcher explicitly in the KDoc for the method in MessageComposerController to make thread-safety expectations clear.stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/viewmodel/messages/MessageComposerViewModel.kt (1)
254-255: Consider adding KDoc for consistency.Similar to the Compose ViewModel, this method would benefit from KDoc documentation to match other public methods in this class and help SDK consumers understand the callback behavior.
📝 Suggested KDoc
+ /** + * Completes audio recording and updates the composer attachments. + * + * `@param` onComplete Optional callback invoked with the result of the recording. + * On success, the recorded [Attachment] is added to [selectedAttachments] before + * the callback is invoked. + */ public fun completeRecording(onComplete: ((Result<Attachment>) -> Unit)? = null): Unit = messageComposerController.completeRecording(onComplete)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/viewmodel/messages/MessageComposerViewModel.kt` around lines 254 - 255, Add KDoc for the public function completeRecording in MessageComposerViewModel describing what the method does, the optional onComplete callback signature (Result<Attachment>), when/why the callback is invoked, and any threading or lifecycle considerations; locate the function declaration "completeRecording(onComplete: ((Result<Attachment>) -> Unit)? = null): Unit" and add a concise `@param` for onComplete and a brief `@return/`@see if applicable to match existing public method docs in this class.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/viewmodel/messages/MessageComposerViewModel.kt`:
- Around line 277-278: Add a KDoc comment for the public function
MessageComposerViewModel.completeRecording explaining its purpose (finalizes the
current audio recording), the optional onComplete callback signature
((Result<Attachment>) -> Unit) and what values the Result conveys (success
contains the created Attachment, failure contains the error), and any
threading/ordering expectations; place the KDoc immediately above the
completeRecording method (which delegates to
messageComposerController.completeRecording) to match the style and detail used
for other public methods like setMessageInput and sendMessage.
In
`@stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/MessageComposerController.kt`:
- Around line 925-930: Update the KDoc for MessageComposerController's
audio-completion method to state the execution context of the onComplete
callback: document that the onComplete callback (invoked after the recorded
Attachment is added to MessageComposerState.attachments/selectedAttachments) is
executed on the main (UI) dispatcher / immediate coroutine context so callers
can safely perform UI updates. Mention the dispatcher explicitly in the KDoc for
the method in MessageComposerController to make thread-safety expectations
clear.
In
`@stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/viewmodel/messages/MessageComposerViewModel.kt`:
- Around line 254-255: Add KDoc for the public function completeRecording in
MessageComposerViewModel describing what the method does, the optional
onComplete callback signature (Result<Attachment>), when/why the callback is
invoked, and any threading or lifecycle considerations; locate the function
declaration "completeRecording(onComplete: ((Result<Attachment>) -> Unit)? =
null): Unit" and add a concise `@param` for onComplete and a brief `@return/`@see if
applicable to match existing public method docs in this class.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: af54a94b-8238-426a-bd58-115de89fb0bc
📒 Files selected for processing (5)
stream-chat-android-compose/api/stream-chat-android-compose.apistream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/viewmodel/messages/MessageComposerViewModel.ktstream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/composer/MessageComposerController.ktstream-chat-android-ui-components/api/stream-chat-android-ui-components.apistream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/viewmodel/messages/MessageComposerViewModel.kt
|
🚀 Available in v6.36.0 |
* Improve `Message.createdLocallyAt` creation logic using estimated server time (#6199) * Fix createdLocallyAt using NTP-style server clock offset estimation Co-Authored-By: Claude <noreply@anthropic.com> * Pr remarks * Adjust thread message createdLocallyAt. * Ensure exceedsSyncThreshold is compared against estimated server time (where applicable). * Add max allowed offset. --------- Co-authored-by: Claude <noreply@anthropic.com> * [skip ci] Update SDK sizes * Update README cover image (#6282) * Fix XML image flicker caused by `interceptorCoroutineContext(Dispatchers.IO)` (#6284) Co-authored-by: Claude <noreply@anthropic.com> * [skip ci] Update SDK sizes * AUTOMATION: Version Bump * Fix race condition in plugin resolution during disconnect (#6269) * Update `DependencyResolverTest` to verify error handling when dependency resolution races with disconnection. * Prevent race conditions during disconnects in `ChatClient`. * Handle unresolvable attachments in picker (#6285) - Update `StorageHelper` and `AttachmentMetaDataMapper` to safely handle cases where content URIs (e.g. cloud-backed files) cannot be opened. - Introduce `hasUnresolvedAttachments` state in `AttachmentsPickerViewModel` to track failed attachment resolutions. - Show a toast message in both View-based and Compose attachment pickers when files are unavailable and need to be downloaded to the device. - Add `clearUnresolvedAttachments` to reset the error state after it has been consumed by the UI. - Add unit tests for unresolved attachment scenarios in `AttachmentsPickerViewModelTest`. * [skip ci] Update SDK sizes * Fix wrong message selected on quoted message long click (#6292) * Use type-specific attachment URL fields and deprecate `imagePreviewUrl` (#6280) * Deprecate imagePreviewUrl and use type-specific attachment URL fields Co-Authored-By: Claude <noreply@anthropic.com> * Extract common extensions. --------- Co-authored-by: Claude <noreply@anthropic.com> * Expose optional completion callback for audio recording (#6290) Co-authored-by: Claude <noreply@anthropic.com> * AUTOMATION: Version Bump * AUTOMATION: Clean Detekt Baseline Files (#6299) Co-authored-by: adasiewiczr <17440581+adasiewiczr@users.noreply.github.com> * Add support for intercepting CDN file requests (#6295) * Add new CDN contract. * Add CDN for document files. * Add CDN support for downloading attachments. * Deprecate current CDN methods. * Add progress indicator snackbar. * Add useDocumentGView config flag. * Add file sharing cache handling. * Add file sharing cache handling. * Remove CDNResponse.kt * Add tests * PR remarks * [skip ci] Update SDK sizes * Post-merge clean-up. * Post-merge clean-up. * ApiDump. * Improve attachment URI resolution and error handling in `AttachmentsPickerViewModel` and `AttachmentStorageHelper`. - Add `isUriResolvable` to `StorageHelper` to verify if a content URI can be opened for reading. - Implement `partitionResolvable` in `AttachmentStorageHelper` to separate metadata based on URI accessibility. - Update `AttachmentsPickerViewModel.resolveAndSubmitUris` to exclude inaccessible URIs (e.g., undownloaded cloud files) from the submission. - Ensure `hasUnresolvedAttachments` is correctly set when URIs are inaccessible, independent of file type support. - Add unit tests in `AttachmentStorageHelperTest` and `AttachmentsPickerViewModelTest` to verify partitioning logic and view model state updates. * Handle unresolvable attachments in XML * apiDump. --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: André Mion <andremion@gmail.com> Co-authored-by: Gianmarco <47775302+gpunto@users.noreply.github.com> Co-authored-by: stream-pr-merger[bot] <117762243+stream-pr-merger[bot]@users.noreply.github.com> Co-authored-by: adasiewiczr <17440581+adasiewiczr@users.noreply.github.com>



Goal
Allow callers to observe when an audio recording completes and receive the resulting
Attachment, so they can perform follow-up actions (e.g. immediately send the message) without relying on state observation.Reason: A customer relied on the
viewModel.completeRecording()completing synchronously, which was changed in: #6036. In this PR we introduce a convenience callback so that customers relying onviewModel.completeRecording()before specific operations have a mechanism to know when the operation is ready.Implementation
onComplete: ((Result<Attachment>) -> Unit)?parameter tocompleteRecording()in:MessageComposerControllerMessageComposerViewModel(Compose)MessageComposerViewModel(UI Components)completeRecordingSync()is used internally. On success the attachment is added toselectedAttachmentsbefore invoking the callback, so callers can safely build a message with it.UI Changes
No UI changes.
Testing
completeRecording()without a callback — verify existing behavior is unchanged.completeRecording { result -> ... }— verify the callback fires withResult.Success<Attachment>after recording completes, and the attachment is present inselectedAttachments.Summary by CodeRabbit