Skip to content

Add option to configure max length for question and option text in polls#1500

Open
martinmitrevski wants to merge 3 commits into
developfrom
polls-max-letter-config
Open

Add option to configure max length for question and option text in polls#1500
martinmitrevski wants to merge 3 commits into
developfrom
polls-max-letter-config

Conversation

@martinmitrevski

@martinmitrevski martinmitrevski commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

πŸ”— Issue Links

Resolves https://linear.app/stream/issue/IOS-1698/swiftuistrava-configure-max-length-for-question-and-option-text.

🎯 Goal

Describe why we are making this change.

πŸ“ Summary

Provide bullet points with the most important changes in the codebase.

πŸ›  Implementation

Provide a detailed description of the implementation and explain your decisions if you find them relevant.

🎨 Showcase

Add relevant screenshots and/or videos/gifs to easily see what this PR changes, if applicable.

Before After
img img

πŸ§ͺ Manual Testing Notes

Explain how this change can be tested manually, if applicable.

β˜‘οΈ Contributor Checklist

  • I have signed the Stream CLA (required)
  • This change should be manually QAed
  • Changelog is updated with client-facing changes
  • Changelog is updated with new localization keys
  • New code is covered by unit tests
  • Documentation has been updated in the docs-content repo

Summary by CodeRabbit

  • New Features
    • Added configurable character limits for poll questions and options to enforce maximum text lengths during poll creation.

@martinmitrevski martinmitrevski requested a review from a team as a code owner June 19, 2026 14:50
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Review Change Stack

πŸ“ Walkthrough

Walkthrough

PollsConfig gains two optional Int properties (maxQuestionLength, maxOptionLength) with nil defaults. CreatePollViewModel reads these at init, enforces them via a private clamped(_:to:) helper in the question property's didSet and in updateOption(id:value:), scheduling async reassignment when truncation occurs. Tests and changelog entry are added.

Changes

Poll Character Limit Enforcement

Layer / File(s) Summary
PollsConfig character limit fields and initializer
Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollsConfig.swift, CHANGELOG.md
Adds maxQuestionLength: Int? and maxOptionLength: Int? properties to PollsConfig with nil defaults, extends the public initializer to accept and assign them, and records the new fields in the changelog.
CreatePollViewModel clamping logic
Sources/StreamChatSwiftUI/ChatComposer/Polls/CreatePollViewModel.swift
Stores both limit values from pollsConfig at init; adds a private clamped(_:to:) helper that truncates text only when a non-nil limit is exceeded; applies clamping in the question didSet and in updateOption(id:value:), scheduling a delayed reassignment via DispatchQueue.main.asyncAfter when truncation occurs.
Character limit tests
StreamChatSwiftUITests/Tests/ChatChannel/CreatePollViewModel_Tests.swift
Adds a "Text Length Limits" test section covering: long input accepted when no limit is set, async truncation to maxQuestionLength/maxOptionLength, within-limit text left unchanged, and emoji-based verification that truncation is character-count rather than byte-count.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

πŸ‡ Hippity-hop, no poll too long,
A maxQuestionLength keeps it strong,
clamped(_:to:) trims the tail,
Emojis counted without fail,
Now polls stay neat β€” the rabbit's song! πŸŽ‰

πŸš₯ Pre-merge checks | βœ… 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
βœ… Passed checks (4 passed)
Check name Status Explanation
Description Check βœ… Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check βœ… Passed The title accurately summarizes the main change: adding configuration options for maximum length limits for poll question and option text.
Linked Issues check βœ… Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check βœ… Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
πŸ“ Generate docstrings
  • Create stacked PR
  • Commit on current branch
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch polls-max-letter-config

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.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

πŸ€– Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Sources/StreamChatSwiftUI/ChatComposer/Polls/CreatePollViewModel.swift`:
- Around line 137-143: The asyncAfter block in the updateOption method is
redundant because the value is already clamped and assigned immediately on the
line before the conditional. Remove the entire if maxOptionLength != nil block
containing the DispatchQueue.main.asyncAfter call, as the synchronous assignment
of the clamped value is sufficient and matches the behavior expected by
test_updateOption_truncatedToMaxOptionLength. This also eliminates the potential
bug where the captured index could become stale if options are reordered or
removed before the delayed closure executes.
πŸͺ„ Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
βš™οΈ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 067cf1db-d583-489d-8af4-e044a4ad11e6

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between b51228e and 81162d5.

πŸ“’ Files selected for processing (4)
  • CHANGELOG.md
  • Sources/StreamChatSwiftUI/ChatComposer/Polls/CreatePollViewModel.swift
  • Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollsConfig.swift
  • StreamChatSwiftUITests/Tests/ChatChannel/CreatePollViewModel_Tests.swift

Comment on lines +137 to +143
let value = clamped(value, to: maxOptionLength)
options[index].text = value
if maxOptionLength != nil {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
self?.options[index].text = value
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟑 Minor | ⚑ Quick win

Remove the redundant asyncAfter assignment.

The value is already clamped and assigned immediately on line 138. The asyncAfter block (lines 139-143) schedules another assignment of the same clamped value, which is unnecessary. Unlike the question property's didSet observer where asyncAfter is needed to handle SwiftUI binding cycles, updateOption is directly called and can clamp synchronously.

The test test_updateOption_truncatedToMaxOptionLength confirms thisβ€”it asserts the clamped value immediately without waiting for async completion.

Additionally, the closure captures index by value, which could become stale if options are reordered or removed before the closure executes 0.1 seconds later, potentially writing to the wrong option or crashing.

πŸ”§ Proposed fix
 func updateOption(id: UUID, value: String) {
     guard let index = options.firstIndex(where: { $0.id == id }) else { return }
     let value = clamped(value, to: maxOptionLength)
     options[index].text = value
-    if maxOptionLength != nil {
-        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
-            self?.options[index].text = value
-        }
-    }
     if index == options.count - 1,
        !value.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
         withAnimation {
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let value = clamped(value, to: maxOptionLength)
options[index].text = value
if maxOptionLength != nil {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
self?.options[index].text = value
}
}
let value = clamped(value, to: maxOptionLength)
options[index].text = value
πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/StreamChatSwiftUI/ChatComposer/Polls/CreatePollViewModel.swift`
around lines 137 - 143, The asyncAfter block in the updateOption method is
redundant because the value is already clamped and assigned immediately on the
line before the conditional. Remove the entire if maxOptionLength != nil block
containing the DispatchQueue.main.asyncAfter call, as the synchronous assignment
of the clamped value is sufficient and matches the behavior expected by
test_updateOption_truncatedToMaxOptionLength. This also eliminates the potential
bug where the captured index could become stale if options are reordered or
removed before the delayed closure executes.

@Stream-SDK-Bot

Copy link
Copy Markdown
Collaborator

SDK Size

title develop branch diff status
StreamChatSwiftUI 8.25 MB 8.25 MB 0 KB 🟒

@nuno-vieira nuno-vieira left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM! βœ…

@Stream-SDK-Bot

Copy link
Copy Markdown
Collaborator

StreamChatSwiftUI XCSize

Object Diff (bytes)
CreatePollViewModel.o +3426
PollsConfig.o +792
MessageViewFactoryOptions.o +108

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.

3 participants