Skip to content

Disable swipe-to-reply for deleted messages#6226

Merged
VelikovPetar merged 2 commits intodevelopfrom
bug/disable_swipe_to_reply_for_deleted_messages
Mar 9, 2026
Merged

Disable swipe-to-reply for deleted messages#6226
VelikovPetar merged 2 commits intodevelopfrom
bug/disable_swipe_to_reply_for_deleted_messages

Conversation

@VelikovPetar
Copy link
Contributor

@VelikovPetar VelikovPetar commented Mar 9, 2026

Goal

Prevent the swipe-to-reply gesture from being triggerable on messages that have been deleted during the current session. Previously, swipeability was computed without memoization, so a message deleted mid-session could still be swiped until the next recomposition. Additionally, canReplyToMessage did not check the deleted state of the message.

Implementation

  • Added !message.isDeleted() check to canReplyToMessage in CapabilitiesHelper so the core logic correctly blocks replies to deleted messages across all UI surfaces (Compose + XML).
  • Refactored isSwipeable in MessageItem to use remember(message, ownCapabilities, optionVisibility) so the swipe state is memoized and re-evaluated reactively when the message is deleted or capabilities/theme change. optionVisibility was missing from the keys, which could produce a stale value if the theme changed at runtime.
  • Updated SwipeToReply to accept isSwipeable: Boolean directly (was () -> Boolean lambda) and aligned pointerInput keys accordingly.
  • Updated test cases in CapabilitiesHelperTest, MessageOptionItemVisibilityTest, and MessageListViewExtensionsKtTest to explicitly cover the deleted-message scenario and add clearer case comments.

Testing

  • Run existing parameterised tests for canReplyToMessage — new test cases cover the deleted-message path returning false.
  • Manually delete a message mid-session and verify the swipe-to-reply gesture is no longer triggerable on it.

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced message reply capability checks to properly account for deletion status, preventing replies to deleted messages.
    • Improved swipe-to-reply feature to correctly handle deleted message scenarios.
  • Tests

    • Expanded test coverage for message capability checks across deleted and non-deleted message states.

Co-Authored-By: Claude <noreply@anthropic.com>
@VelikovPetar VelikovPetar added the pr:bug Bug fix label Mar 9, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 9, 2026

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled.

🎉 Great job! This PR is ready for review.

@VelikovPetar VelikovPetar marked this pull request as ready for review March 9, 2026 08:47
@VelikovPetar VelikovPetar requested a review from a team as a code owner March 9, 2026 08:47
@github-actions
Copy link
Contributor

github-actions bot commented Mar 9, 2026

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 5.26 MB 5.26 MB 0.00 MB 🟢
stream-chat-android-offline 5.48 MB 5.48 MB 0.00 MB 🟢
stream-chat-android-ui-components 10.63 MB 10.63 MB 0.00 MB 🟢
stream-chat-android-compose 12.85 MB 12.85 MB 0.00 MB 🟢

@coderabbitai
Copy link

coderabbitai bot commented Mar 9, 2026

Walkthrough

The changes introduce a deleted message check to the reply-to-message capability, preventing users from replying to deleted messages. The SwipeToReply composable API is simplified from a lambda-based approach to a boolean flag, and test coverage is expanded to validate deleted message scenarios across capability checks.

Changes

Cohort / File(s) Summary
Composable API Refactor
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/list/MessageItem.kt
Changed SwipeToReply parameter from isSwipeable: () -> Boolean (lambda) to isSwipeable: Boolean (direct flag). Updated call site and internal pointerInput guard accordingly. Renamed local variable for consistency.
Capability Logic
stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/utils/CapabilitiesHelper.kt
Enhanced canReplyToMessage to additionally validate that the message is not deleted (!message.isDeleted), in addition to existing sync and capability checks.
Test Coverage Expansion
stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/util/extensions/MessageOptionItemVisibilityTest.kt, stream-chat-android-ui-common/src/test/kotlin/io/getstream/chat/android/ui/common/utils/CapabilitiesHelperTest.kt, stream-chat-android-ui-components/src/test/kotlin/io/getstream/chat/android/ui/feature/messages/list/internal/MessageListViewExtensionsKtTest.kt
Added test scenarios covering deleted message states and reply capability edge cases. Test data now includes explicit deletedAt and deletedForMe parameters to validate deletion checks across capability scenarios.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A rabbit hops with glee,
No replies to messages deleted shall be!
Simpler APIs, boolean and bright,
Tests now cover every plight—
Capabilities checked, all done right! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: disabling swipe-to-reply for deleted messages, which aligns with the primary objective and all code changes.
Description check ✅ Passed The description includes Goal and Implementation sections with clear, detailed explanations of the changes. However, the UI Changes section with screenshots/videos is missing, and the contributor/reviewer checklists are incomplete.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch bug/disable_swipe_to_reply_for_deleted_messages

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

Copy link

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
stream-chat-android-ui-common/src/test/kotlin/io/getstream/chat/android/ui/common/utils/CapabilitiesHelperTest.kt (1)

198-203: ⚠️ Potential issue | 🟡 Minor

Misleading comment: "message not synced" doesn't match the test scenario.

This test case excludes READ_EVENTS capability for canMarkAsUnread, not testing sync status.

📝 Suggested fix
-            // case: message not synced
+            // case: no READ_EVENTS capability
             Arguments.of(
                 randomBoolean(),
                 randomChannelCapabilities(exclude = setOf(ChannelCapabilities.READ_EVENTS)),
                 false,
             ),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@stream-chat-android-ui-common/src/test/kotlin/io/getstream/chat/android/ui/common/utils/CapabilitiesHelperTest.kt`
around lines 198 - 203, The comment "message not synced" is misleading for the
Arguments.of case in CapabilitiesHelperTest; update the comment to reflect that
this case is testing canMarkAsUnread behavior when the channel lacks
ChannelCapabilities.READ_EVENTS (use symbols like canMarkAsUnread,
ChannelCapabilities.READ_EVENTS, randomChannelCapabilities, and
CapabilitiesHelperTest to locate the test), e.g., change the comment to
something like "case: READ_EVENTS capability missing for canMarkAsUnread" so it
accurately describes the scenario.
stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/util/extensions/MessageOptionItemVisibilityTest.kt (1)

203-207: ⚠️ Potential issue | 🟡 Minor

Misleading comment: "message not synced" doesn't match the test scenario.

This test case excludes READ_EVENTS capability, not testing sync status. The comment should reflect what's actually being tested.

📝 Suggested fix
-            // case: message not synced
+            // case: no READ_EVENTS capability
             Arguments.of(
                 MessageOptionItemVisibility(),
                 randomChannelCapabilities(exclude = setOf(ChannelCapabilities.READ_EVENTS)),
                 false,
             ),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/util/extensions/MessageOptionItemVisibilityTest.kt`
around lines 203 - 207, The comment above the test case is misleading — it says
"message not synced" but the test actually constructs a scenario excluding
ChannelCapabilities.READ_EVENTS via randomChannelCapabilities; update the
comment to accurately describe the scenario being tested (e.g., "channel missing
READ_EVENTS capability" or similar) next to the Arguments.of that uses
MessageOptionItemVisibility and randomChannelCapabilities(exclude =
setOf(ChannelCapabilities.READ_EVENTS)) so the comment matches the intent.
🧹 Nitpick comments (1)
stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/utils/CapabilitiesHelper.kt (1)

46-66: KDoc should document the deleted message condition.

The KDoc lists conditions for when a reply is allowed but omits the newly added requirement that the message must not be deleted. Update the documentation to include this condition:

📝 Suggested KDoc update
 /**
  * Determines whether a reply (quote) can be made to the given message.
  *
  * A reply is allowed when:
  * - Reply functionality is enabled in the UI configuration
  * - The message has been successfully synced with the backend
+ * - The message has not been deleted
  * - The user has the capability to quote messages in the channel
  *
🤖 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/utils/CapabilitiesHelper.kt`
around lines 46 - 66, The KDoc for canReplyToMessage is missing the condition
that the message must not be deleted; update the documentation to state that
replies are only allowed when replyEnabled is true, the message is synced
(message.isSynced()), the message is not deleted (i.e., !message.isDeleted()),
and the user has the ChannelCapabilities.QUOTE_MESSAGE capability in
ownCapabilities; reference canReplyToMessage, message.isDeleted(),
message.isSynced(), and ChannelCapabilities.QUOTE_MESSAGE in the updated
comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/list/MessageItem.kt`:
- Line 737: The KDoc for the isSwipeable parameter in MessageItem.kt contains a
typo "swipe-te-reply"; update the documentation for the isSwipeable parameter
(in the MessageItem composable / function signature) to read "swipe-to-reply"
instead of "swipe-te-reply" so the param description is correct.

In
`@stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/util/extensions/MessageOptionItemVisibilityTest.kt`:
- Around line 224-234: Update the misleading inline comment above this test case
so it accurately describes the scenario being tested: replace "no QUOTE_MESSAGE
capability" with a comment stating that this `Arguments.of` entry is testing a
non-COMPLETED sync status for `randomMessage` (using `randomSyncStatus(exclude =
listOf(SyncStatus.COMPLETED))`) in the `canPinMessageArguments` set; reference
the involved symbols `MessageOptionItemVisibility()`, `randomMessage`,
`randomSyncStatus`, `SyncStatus.COMPLETED`, and `randomChannelCapabilities` to
make the intent clear.

In
`@stream-chat-android-ui-common/src/test/kotlin/io/getstream/chat/android/ui/common/utils/CapabilitiesHelperTest.kt`:
- Around line 219-229: The comment "no QUOTE_MESSAGE capability" above the
Arguments.of in CapabilitiesHelperTest is inaccurate for the
canPinMessageArguments test; update or remove it so it reflects the actual
scenario being tested (a message with non-COMPLETED sync status and not deleted:
see the Arguments.of that passes randomSyncStatus(exclude =
listOf(SyncStatus.COMPLETED)), deletedAt = null, deletedForMe = false) or
replace it with a clear comment like "case: message sync status is not COMPLETED
(cannot pin)"; adjust the comment near the Arguments.of to correctly describe
the test inputs referenced in canPinMessageArguments.

---

Outside diff comments:
In
`@stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/util/extensions/MessageOptionItemVisibilityTest.kt`:
- Around line 203-207: The comment above the test case is misleading — it says
"message not synced" but the test actually constructs a scenario excluding
ChannelCapabilities.READ_EVENTS via randomChannelCapabilities; update the
comment to accurately describe the scenario being tested (e.g., "channel missing
READ_EVENTS capability" or similar) next to the Arguments.of that uses
MessageOptionItemVisibility and randomChannelCapabilities(exclude =
setOf(ChannelCapabilities.READ_EVENTS)) so the comment matches the intent.

In
`@stream-chat-android-ui-common/src/test/kotlin/io/getstream/chat/android/ui/common/utils/CapabilitiesHelperTest.kt`:
- Around line 198-203: The comment "message not synced" is misleading for the
Arguments.of case in CapabilitiesHelperTest; update the comment to reflect that
this case is testing canMarkAsUnread behavior when the channel lacks
ChannelCapabilities.READ_EVENTS (use symbols like canMarkAsUnread,
ChannelCapabilities.READ_EVENTS, randomChannelCapabilities, and
CapabilitiesHelperTest to locate the test), e.g., change the comment to
something like "case: READ_EVENTS capability missing for canMarkAsUnread" so it
accurately describes the scenario.

---

Nitpick comments:
In
`@stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/utils/CapabilitiesHelper.kt`:
- Around line 46-66: The KDoc for canReplyToMessage is missing the condition
that the message must not be deleted; update the documentation to state that
replies are only allowed when replyEnabled is true, the message is synced
(message.isSynced()), the message is not deleted (i.e., !message.isDeleted()),
and the user has the ChannelCapabilities.QUOTE_MESSAGE capability in
ownCapabilities; reference canReplyToMessage, message.isDeleted(),
message.isSynced(), and ChannelCapabilities.QUOTE_MESSAGE in the updated
comment.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e72998bd-f4d4-40c9-a6f0-326f85e6e154

📥 Commits

Reviewing files that changed from the base of the PR and between 3b5cd86 and e0137d9.

📒 Files selected for processing (5)
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/list/MessageItem.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/util/extensions/MessageOptionItemVisibilityTest.kt
  • stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/utils/CapabilitiesHelper.kt
  • stream-chat-android-ui-common/src/test/kotlin/io/getstream/chat/android/ui/common/utils/CapabilitiesHelperTest.kt
  • stream-chat-android-ui-components/src/test/kotlin/io/getstream/chat/android/ui/feature/messages/list/internal/MessageListViewExtensionsKtTest.kt

@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 9, 2026

@VelikovPetar VelikovPetar merged commit 56a1073 into develop Mar 9, 2026
15 checks passed
@VelikovPetar VelikovPetar deleted the bug/disable_swipe_to_reply_for_deleted_messages branch March 9, 2026 09:56
@stream-public-bot stream-public-bot added the released Included in a release label Mar 13, 2026
@stream-public-bot
Copy link
Contributor

🚀 Available in v6.35.0

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

Labels

pr:bug Bug fix released Included in a release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants