Skip to content

Refactor poll switch config and update multiple votes design and logic#6224

Draft
gpunto wants to merge 7 commits intov7from
redesign/poll-creation-multiple-votes-split
Draft

Refactor poll switch config and update multiple votes design and logic#6224
gpunto wants to merge 7 commits intov7from
redesign/poll-creation-multiple-votes-split

Conversation

@gpunto
Copy link
Contributor

@gpunto gpunto commented Mar 6, 2026

Goal

Replace PollSwitchItemFactory with a simpler PollsConfig in ChatConfig and split the "multiple votes" switch into separate toggles for enabling multiple votes and limiting votes per person.

Implementation

  • Remove PollSwitchItem, PollSwitchInput, PollSwitchItemFactory, and PollOptionNumberExceed
  • Add PollsConfig / PollFeatureConfig to ChatConfig to control feature visibility and defaults
  • Replace generic switch list with typed PollSwitchState sealed class and individual state fields in the ViewModel
  • Split "multiple votes" into a main toggle, a child "limit votes" toggle, and a Stepper input

🎨 UI Changes

Before After

Testing

  • Verify all poll creation toggles render and behave correctly
  • Test stepper bounds and manual input
  • Create polls with various configs and confirm correct PollConfig

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced poll configuration with new settings for limiting votes per person, toggling multiple votes, anonymous polls, suggested options, and poll comments.
    • Improved poll creation UI with step controls for vote limits.
  • Bug Fixes & Improvements

    • Refined terminology: "Multiple answers" renamed to "Multiple votes" for clarity.
    • Streamlined poll settings management with updated configuration controls.

@gpunto gpunto added pr:breaking-change Breaking change pr:improvement Improvement labels Mar 6, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 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.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 5.25 MB 5.69 MB 0.44 MB 🟡
stream-chat-android-ui-components 10.60 MB 11.00 MB 0.40 MB 🟡
stream-chat-android-compose 12.81 MB 12.02 MB -0.79 MB 🚀

@gpunto
Copy link
Contributor Author

gpunto commented Mar 9, 2026

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Mar 9, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link

coderabbitai bot commented Mar 9, 2026

Walkthrough

The pull request refactors the poll feature configuration system by replacing a factory-based switch list model with a declarative configuration object. It removes old PollSwitchItem infrastructure and introduces PollFeatureConfig and PollsConfig classes integrated into ChatConfig and ChatTheme. The CreatePollViewModel now manages individual toggle states instead of a mutable list, and PollSwitchList composable is converted to an internal state-driven component. Related tests and string resources are updated accordingly.

Changes

Cohort / File(s) Summary
Poll Configuration Model
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatConfig.kt, stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatTheme.kt, stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatThemeKt
Added new PollFeatureConfig and PollsConfig classes. Extended ChatConfig with polls member and updated ChatTheme to expose getPolls() while removing pollSwitchitemFactory. Updated public API surface to include new configuration in chat theming.
Poll ViewModel & State Management
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollViewModel.kt, stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollViewModelFactory.kt
Replaced configSwitches parameter with PollsConfig. Refactored CreatePollViewState from switchItemList to granular toggle fields (multipleVotes, limitVotesPerPerson, maxVotesPerPersonText, anonymousPoll, suggestAnOption, allowComments). Added per-feature update methods and initialState() helper.
Poll Composables & Utilities
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchList.kt, stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollScreen.kt, stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/AttachmentsPickerPollUtils.kt
Converted PollSwitchList from public mutable API to internal state-driven composable with explicit toggle parameters. Updated CreatePollScreen to use ChatTheme.config.polls and pass state instead of switchItemList. Refactored pollConfigFrom() to accept CreatePollViewState instead of List.
Removed Infrastructure
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchItem.kt, stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/util/PollSwitchItemFactory.kt, stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionError.kt
Deleted PollSwitchItem.kt (including PollSwitchItem and PollSwitchInput classes). Deleted entire PollSwitchItemFactory.kt (interface and DefaultPollSwitchItemFactory). Removed PollOptionNumberExceed variant from PollOptionError sealed class.
Resources & Constants
stream-chat-android-compose/src/main/res/values/strings.xml, stream-chat-android-compose/src/main/res/drawable/stream_compose_ic_minus.xml, stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/utils/PollsConstants.kt
Renamed "Multiple answers" to "Multiple votes" in poll strings. Added limit votes UI strings (title, description, increase/decrease buttons, input label). Added stream_compose_ic_minus.xml drawable. Added MULTIPLE_ANSWERS_RANGE constant to PollsConstants.
Test Updates
stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/poll/AttachmentsPickerPollUtilsTest.kt, stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollViewModelTest.kt, stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchListTest.kt
Updated tests to use CreatePollViewState and PollsConfig instead of factory-based switches. Refactored CreatePollViewModelTest to use defaultConfig and added tests for new toggle update methods. Updated PollSwitchListTest to render PollSwitchListPreviewContent.
Removed Test Files
stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchInputErrorTest.kt, stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/util/DefaultPollSwitchItemFactoryTest.kt
Deleted test files for removed classes PollSwitchInput and DefaultPollSwitchItemFactory.
Configuration
stream-chat-android-compose/api/stream-chat-android-compose.api, stream-chat-android-compose/detekt-baseline.xml
Updated public API surface to reflect removal of poll switch infrastructure and addition of PollFeatureConfig/PollsConfig classes. Removed corresponding detekt baseline entries.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • VelikovPetar

Poem

🐰 Polls now bloom with cleaner design,
Config objects make features align,
No more factories cluttering the way,
State-driven toggles save the day!
Hopping forward with refactored grace.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.09% 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 specifically describes the main change: refactoring poll switch configuration and splitting multiple votes design.
Description check ✅ Passed The description includes Goal, Implementation, and Testing sections with clear details, though UI Changes table lacks actual screenshots and Before/After images are missing.

✏️ 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 redesign/poll-creation-multiple-votes-split

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: 5

🧹 Nitpick comments (3)
stream-chat-android-compose/src/main/res/values/strings.xml (1)

321-322: Avoid hardcoding the vote limits in the description.

PollSwitchList already enforces PollsConstants.MULTIPLE_ANSWERS_RANGE, so the "2–10" copy can drift from the actual bounds. A formatted string (%1$d–%2$d) passed from the composable keeps the text and validation in sync.

♻️ Suggested shape
-    <string name="stream_compose_poll_option_limit_votes_description">Choose between 2\u201310 options</string>
+    <string name="stream_compose_poll_option_limit_votes_description">Choose between %1$d\u2013%2$d votes</string>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@stream-chat-android-compose/src/main/res/values/strings.xml` around lines 321
- 322, The string hardcodes "2–10" and can drift from
PollsConstants.MULTIPLE_ANSWERS_RANGE; change the resource
stream_compose_poll_option_limit_votes_description to a formatted string with
placeholders (e.g. "%1$d–%2$d") and update the composable that renders this text
(where PollSwitchList or its parent sets the description) to pass
PollsConstants.MULTIPLE_ANSWERS_RANGE.first and .last (or equivalent bounds)
into the formatted string so the UI text stays in sync with the validation
constants.
stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/poll/AttachmentsPickerPollUtilsTest.kt (2)

57-120: Add a bounds/manual-input case for maxVotesPerUserText.

The new pollConfigFrom branch now parses, clamps, and defaults invalid manual input, but this suite only covers already-valid values. A focused case for blank/non-numeric input and an out-of-range value would pin that behavior down.

🤖 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/ui/messages/attachments/poll/AttachmentsPickerPollUtilsTest.kt`
around lines 57 - 120, Add tests for pollConfigFrom that cover manual-input edge
cases for maxVotesPerUserText: one test where maxVotesPerUserText is blank or
non-numeric (e.g., "") and limitVotesEnabled = true to assert maxVotesAllowed
becomes null or the default behavior, and one test where maxVotesPerUserText is
out-of-range (e.g., "999" or "-1") to assert the value is clamped to the allowed
bounds; construct CreatePollViewState with multipleVotesEnabled and
limitVotesEnabled true, call pollConfigFrom(question, options, state) and assert
the resulting PollConfig.maxVotesAllowed matches the expected clamped/default
values while other fields (name, options, votingVisibility, enforceUniqueVote,
allowUserSuggestedOptions, allowAnswers) remain as in existing tests.

27-28: Use backtick test names for these Kotlin tests.

These new methods fall back to test... naming, which is inconsistent with the test style used elsewhere in this module.

As per coding guidelines, **/src/test/**/*.kt: Use backtick test names (for example: fun message list filters muted channels()) for readability.

Also applies to: 57-57, 87-87

🤖 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/ui/messages/attachments/poll/AttachmentsPickerPollUtilsTest.kt`
around lines 27 - 28, The test functions in AttachmentsPickerPollUtilsTest
(notably testPollConfigWithAllDisabled and the two other test methods in this
file) use Java-style names; rename them to Kotlin backtick-style descriptive
names (e.g., replace testPollConfigWithAllDisabled with a backtick name like
`poll config with all options disabled`) to match the project's test naming
convention; update the function declarations and any references/imports
accordingly so the tests still run under the same class (ensure the method
signatures remain parameterless and annotated with `@Test`).
🤖 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/api/stream-chat-android-compose.api`:
- Around line 3520-3538: PollsConfig currently exposes PollFeatureConfig for
multipleVotes, anonymousPoll, allowComments, and suggestAnOption but does not
expose the new “limitVotes” child toggle, while CreatePollViewModel still keeps
limitVotes state outside the config; update the public PollsConfig API to
include a PollFeatureConfig field for limitVotes (add property, getter
getLimitVotes(), update constructors, componentN, copy and copy$default,
equals/hashCode/toString as needed) so consumers can configure limitVotes
alongside multipleVotes and the other child toggles and then use that field in
CreatePollViewModel instead of keeping limitVotes as an internal-only state.
- Around line 3084-3085: Add a CHANGELOG.md entry under
stream-chat-android-compose in the ⚠️ Changed or ❌ Removed section explaining
that the public PollSwitchItemFactory and any related factory types were removed
and replaced by the new ChatConfig.polls parameter backed by PollFeatureConfig
and PollsConfig; include a short migration snippet showing the old usage with
PollSwitchItemFactory and how to replace it with constructing/setting
ChatConfig.polls = PollsConfig(...) (mention PollFeatureConfig where applicable)
so Java/Kotlin integrators can map the factory pattern to the new config object
approach.

In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollViewModel.kt`:
- Around line 217-219: The current hasChanges(CreatePollViewState) only checks
question and option titles, so toggling switches or editing maxVotesPerUserText
doesn't register as changes; update hasChanges to also consider the boolean
switch fields (e.g., allowMultipleVotes / isAnonymous / allowComments — use the
actual property names on CreatePollViewState) and the maxVotesPerUserText
string, comparing each to the original/initial CreatePollViewState values (the
stored initial state field in the ViewModel, e.g., initialState or similar) so
any change to those switches or the maxVotesPerUserText returns true.
- Around line 118-121: The seed for switchItems must be the transformed current
state instead of emptyList(): when creating switchItems via .stateIn(scope =
viewModelScope, ...), set initialValue to the result of mapping _state.value
into the same switch-item list (or compute it upfront) so the first collector
sees the real switches; locate the switchItems/stateIn call and replace
initialValue = emptyList() with _state.value.let { /* build same switches from
it */ }. Also update hasChanges (and any helpers using initialState()) to
compare all toggle fields (multipleVotesEnabled, limitVotesEnabled,
maxVotesPerUserText, anonymousPollEnabled, suggestAnOptionEnabled,
allowCommentsEnabled) against their values in initialState() in addition to
question and optionItemList so toggling any of those marks the form as changed.

In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchList.kt`:
- Around line 285-307: The stepper controls and numeric field lack accessibility
labels; update the StepperButton instances (the decrement and increment buttons)
to provide meaningful contentDescription/semantic labels (e.g., "Decrease votes
per person" and "Increase votes per person") and add a semantic
contentDescription or label for the BasicTextField (e.g., "Votes per person")
via its Modifier.semantics/clearAndSetSemantics so TalkBack can announce the
control and its purpose; ensure you use localized string resources and apply the
same changes to the other occurrence around the Block that uses
StepperButton/BasicTextField (the second instance noted).

---

Nitpick comments:
In `@stream-chat-android-compose/src/main/res/values/strings.xml`:
- Around line 321-322: The string hardcodes "2–10" and can drift from
PollsConstants.MULTIPLE_ANSWERS_RANGE; change the resource
stream_compose_poll_option_limit_votes_description to a formatted string with
placeholders (e.g. "%1$d–%2$d") and update the composable that renders this text
(where PollSwitchList or its parent sets the description) to pass
PollsConstants.MULTIPLE_ANSWERS_RANGE.first and .last (or equivalent bounds)
into the formatted string so the UI text stays in sync with the validation
constants.

In
`@stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/poll/AttachmentsPickerPollUtilsTest.kt`:
- Around line 57-120: Add tests for pollConfigFrom that cover manual-input edge
cases for maxVotesPerUserText: one test where maxVotesPerUserText is blank or
non-numeric (e.g., "") and limitVotesEnabled = true to assert maxVotesAllowed
becomes null or the default behavior, and one test where maxVotesPerUserText is
out-of-range (e.g., "999" or "-1") to assert the value is clamped to the allowed
bounds; construct CreatePollViewState with multipleVotesEnabled and
limitVotesEnabled true, call pollConfigFrom(question, options, state) and assert
the resulting PollConfig.maxVotesAllowed matches the expected clamped/default
values while other fields (name, options, votingVisibility, enforceUniqueVote,
allowUserSuggestedOptions, allowAnswers) remain as in existing tests.
- Around line 27-28: The test functions in AttachmentsPickerPollUtilsTest
(notably testPollConfigWithAllDisabled and the two other test methods in this
file) use Java-style names; rename them to Kotlin backtick-style descriptive
names (e.g., replace testPollConfigWithAllDisabled with a backtick name like
`poll config with all options disabled`) to match the project's test naming
convention; update the function declarations and any references/imports
accordingly so the tests still run under the same class (ensure the method
signatures remain parameterless and annotated with `@Test`).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 6e089806-d152-484a-9853-3b8aebcddde4

📥 Commits

Reviewing files that changed from the base of the PR and between cf78e2e and 82834d9.

⛔ Files ignored due to path filters (3)
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages.attachments.poll_CreatePollScreenTest_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages.attachments.poll_CreatePollScreenTest_light_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages.attachments.poll_PollSwitchListTest_list_items.png is excluded by !**/*.png
📒 Files selected for processing (21)
  • stream-chat-android-compose/api/stream-chat-android-compose.api
  • stream-chat-android-compose/detekt-baseline.xml
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/AttachmentsPickerPollUtils.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollScreen.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollViewModel.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollViewModelFactory.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionError.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchItem.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchList.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchState.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatConfig.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatTheme.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/util/PollSwitchItemFactory.kt
  • stream-chat-android-compose/src/main/res/drawable/stream_compose_ic_minus.xml
  • stream-chat-android-compose/src/main/res/values/strings.xml
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/poll/AttachmentsPickerPollUtilsTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollViewModelTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchInputErrorTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/util/DefaultPollSwitchItemFactoryTest.kt
  • stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/utils/PollsConstants.kt
  • stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/composer/attachment/picker/poll/CreatePollViewModel.kt
💤 Files with no reviewable changes (7)
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchItem.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/util/DefaultPollSwitchItemFactoryTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchInputErrorTest.kt
  • stream-chat-android-compose/detekt-baseline.xml
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatTheme.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionError.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/util/PollSwitchItemFactory.kt

@gpunto gpunto force-pushed the redesign/poll-creation-multiple-votes-split branch from 82834d9 to 890ff9f Compare March 9, 2026 11:53
@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 9, 2026

@gpunto
Copy link
Contributor Author

gpunto commented Mar 9, 2026

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Mar 9, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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: 1

♻️ Duplicate comments (1)
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollViewModel.kt (1)

205-206: ⚠️ Potential issue | 🟠 Major

Track toggle-only edits in hasChanges.

Line 205 still ignores the new toggle fields and maxVotesPerPersonText. A user can change only these controls, close the screen, and lose the changes because the form still looks clean.

💡 Suggested fix
 private fun hasChanges(state: CreatePollViewState): Boolean {
-    return state.question.isNotBlank() || state.optionItemList.any { it.title.isNotBlank() }
+    val initial = initialState()
+    return state.question.isNotBlank() ||
+        state.optionItemList.any { it.title.isNotBlank() } ||
+        state.multipleVotes.enabled != initial.multipleVotes.enabled ||
+        state.limitVotesPerPerson.enabled != initial.limitVotesPerPerson.enabled ||
+        state.maxVotesPerPersonText != initial.maxVotesPerPersonText ||
+        state.anonymousPoll.enabled != initial.anonymousPoll.enabled ||
+        state.suggestAnOption.enabled != initial.suggestAnOption.enabled ||
+        state.allowComments.enabled != initial.allowComments.enabled
 }
🤖 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/ui/messages/attachments/poll/CreatePollViewModel.kt`
around lines 205 - 206, Update hasChanges to also consider the poll toggles and
the maxVotesPerPersonText so toggle-only edits are detected: add checks for
state.maxVotesPerPersonText.isNotBlank() and for each boolean toggle property on
CreatePollViewState (the newly added toggle fields) in the return expression of
hasChanges along with the existing question and option title checks; ensure the
method inspects any per-option toggle flags if present on optionItemList as well
so changing only toggle switches registers as a change.
🧹 Nitpick comments (4)
stream-chat-android-compose/api/stream-chat-android-compose.api (1)

3520-3537: Rename maxVotesPerPerson to match the boolean toggle it actually configures.

This property is a PollFeatureConfig, so it controls the child switch state, not the numeric vote cap itself. As a public API name, maxVotesPerPerson reads like the actual integer limit and is easy to misuse from Java/Kotlin. Something like limitVotes / limitVotesPerPerson would better match the redesigned flow; otherwise consider exposing the numeric default separately.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@stream-chat-android-compose/api/stream-chat-android-compose.api` around lines
3520 - 3537, The PollsConfig public API exposes a misleading property named
maxVotesPerPerson (a PollFeatureConfig) — rename it to limitVotesPerPerson (or
limitVotesPerPerson) throughout the class (constructor parameters, property
name, component3, copy/copy$default signatures, getMaxVotesPerPerson ->
getLimitVotesPerPerson, and any synthetic constructors) so the name reflects it
controls the child toggle rather than an integer; to preserve callers, add a
deprecated getMaxVotesPerPerson() that delegates to the new
getLimitVotesPerPerson() (and similarly preserve old copy/constructor overloads
by forwarding to the renamed members) and update all internal usages to the new
identifier.
stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchList.kt (2)

75-86: Consider grouping parameters if this grows further.

SonarCloud flags 8 parameters. The current design aligns directly with CreatePollViewState fields, which simplifies the call site in CreatePollScreen. If more toggles are added, consider introducing a dedicated state holder or passing the entire CreatePollViewState. For now, the trade-off is acceptable.

🤖 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/ui/messages/attachments/poll/PollSwitchList.kt`
around lines 75 - 86, PollSwitchList currently accepts eight separate parameters
which triggers SonarCloud's long-parameter-list flag; to address this, introduce
a small value holder (e.g., PollSwitchState or reuse CreatePollViewState) that
groups the toggle items and related callbacks (such as
onMaxVotesChanged/onMaxVotesFocusLost and maxVotesPerPersonText) and update the
PollSwitchList signature to take that single state object (or the existing
CreatePollViewState) so callers (e.g., CreatePollScreen) pass one aggregated
argument instead of many individual parameters.

151-158: Minor: Redundant border when background has same color.

The border color backgroundCoreSurface matches the background, making the border effectively invisible. If this is intentional (for consistent spacing/structure), consider documenting it. Otherwise, the border can be removed.

🤖 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/ui/messages/attachments/poll/PollSwitchList.kt`
around lines 151 - 158, The border in the Modifier chain inside PollSwitchList
(the .border(width = 1.dp, color = ChatTheme.colors.backgroundCoreSurface, shape
= RoundedCornerShape(StreamTokens.radiusXl)) call) is redundant because its
color equals the background; remove that .border(...) call from the Modifier
chain in PollSwitchList.kt to avoid a no-op border, or if the border is
intentionally used for layout, replace the color with a visible token (e.g.,
ChatTheme.colors.border) or add a brief inline comment above the Modifier
explaining the intentional use for spacing/structure.
stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/poll/AttachmentsPickerPollUtilsTest.kt (1)

27-120: Optional: Consider backtick test names for readability.

Per coding guidelines, test functions should use backtick names (e.g., fun `poll config with all disabled should produce expected defaults`()). However, if the existing codebase consistently uses camelCase, maintaining consistency may be preferable.

🤖 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/ui/messages/attachments/poll/AttachmentsPickerPollUtilsTest.kt`
around lines 27 - 120, The test names (testPollConfigWithAllDisabled,
testPollConfigWithMultipleVotesNoLimit, testPollConfigWithAllEnabled) should use
descriptive backtick method names for readability; rename each function to a
backtick-style name (for example `poll config with all disabled should produce
expected defaults`, `poll config with multiple votes no limit should produce
expected config`, `poll config with all enabled should produce expected config`)
while keeping the existing test bodies and assertions unchanged, or if the
project prefers camelCase, leave the names as-is to preserve consistency.
🤖 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/attachments/poll/CreatePollViewModel.kt`:
- Around line 209-210: The current hasError(CreatePollViewState) only checks
optionItemList.pollOptionError and misses validating max-votes input; update
hasError to also treat invalid max-votes as an error by returning true when
state.limitVotesPerPerson is true and the max-votes input is blank/out-of-range
or when a parsed/validated field (e.g., state.maxVotesPerPersonError or the
validation logic used by AttachmentsPickerPollUtils.pollConfigFrom) indicates
invalid input; locate hasError and incorporate the additional check so creation
is blocked when limitVotesPerPerson is enabled and max votes are invalid.

---

Duplicate comments:
In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollViewModel.kt`:
- Around line 205-206: Update hasChanges to also consider the poll toggles and
the maxVotesPerPersonText so toggle-only edits are detected: add checks for
state.maxVotesPerPersonText.isNotBlank() and for each boolean toggle property on
CreatePollViewState (the newly added toggle fields) in the return expression of
hasChanges along with the existing question and option title checks; ensure the
method inspects any per-option toggle flags if present on optionItemList as well
so changing only toggle switches registers as a change.

---

Nitpick comments:
In `@stream-chat-android-compose/api/stream-chat-android-compose.api`:
- Around line 3520-3537: The PollsConfig public API exposes a misleading
property named maxVotesPerPerson (a PollFeatureConfig) — rename it to
limitVotesPerPerson (or limitVotesPerPerson) throughout the class (constructor
parameters, property name, component3, copy/copy$default signatures,
getMaxVotesPerPerson -> getLimitVotesPerPerson, and any synthetic constructors)
so the name reflects it controls the child toggle rather than an integer; to
preserve callers, add a deprecated getMaxVotesPerPerson() that delegates to the
new getLimitVotesPerPerson() (and similarly preserve old copy/constructor
overloads by forwarding to the renamed members) and update all internal usages
to the new identifier.

In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchList.kt`:
- Around line 75-86: PollSwitchList currently accepts eight separate parameters
which triggers SonarCloud's long-parameter-list flag; to address this, introduce
a small value holder (e.g., PollSwitchState or reuse CreatePollViewState) that
groups the toggle items and related callbacks (such as
onMaxVotesChanged/onMaxVotesFocusLost and maxVotesPerPersonText) and update the
PollSwitchList signature to take that single state object (or the existing
CreatePollViewState) so callers (e.g., CreatePollScreen) pass one aggregated
argument instead of many individual parameters.
- Around line 151-158: The border in the Modifier chain inside PollSwitchList
(the .border(width = 1.dp, color = ChatTheme.colors.backgroundCoreSurface, shape
= RoundedCornerShape(StreamTokens.radiusXl)) call) is redundant because its
color equals the background; remove that .border(...) call from the Modifier
chain in PollSwitchList.kt to avoid a no-op border, or if the border is
intentionally used for layout, replace the color with a visible token (e.g.,
ChatTheme.colors.border) or add a brief inline comment above the Modifier
explaining the intentional use for spacing/structure.

In
`@stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/poll/AttachmentsPickerPollUtilsTest.kt`:
- Around line 27-120: The test names (testPollConfigWithAllDisabled,
testPollConfigWithMultipleVotesNoLimit, testPollConfigWithAllEnabled) should use
descriptive backtick method names for readability; rename each function to a
backtick-style name (for example `poll config with all disabled should produce
expected defaults`, `poll config with multiple votes no limit should produce
expected config`, `poll config with all enabled should produce expected config`)
while keeping the existing test bodies and assertions unchanged, or if the
project prefers camelCase, leave the names as-is to preserve consistency.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7315c480-ae0f-4220-a632-eb97f4b0b093

📥 Commits

Reviewing files that changed from the base of the PR and between 82834d9 and 890ff9f.

⛔ Files ignored due to path filters (5)
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_DirectChannelInfoContentTest_content.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_DirectChannelInfoContentTest_content_in_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages.attachments.poll_CreatePollScreenTest_dark_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages.attachments.poll_CreatePollScreenTest_light_mode.png is excluded by !**/*.png
  • stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages.attachments.poll_PollSwitchListTest_list_items.png is excluded by !**/*.png
📒 Files selected for processing (21)
  • stream-chat-android-compose/api/stream-chat-android-compose.api
  • stream-chat-android-compose/detekt-baseline.xml
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/AttachmentsPickerPollUtils.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollScreen.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollViewModel.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollViewModelFactory.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionError.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchItem.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchList.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatConfig.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatTheme.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/util/PollSwitchItemFactory.kt
  • stream-chat-android-compose/src/main/res/drawable/stream_compose_ic_minus.xml
  • stream-chat-android-compose/src/main/res/values/strings.xml
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/poll/AttachmentsPickerPollUtilsTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/poll/CreatePollViewModelTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchInputErrorTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchListTest.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/util/DefaultPollSwitchItemFactoryTest.kt
  • stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/utils/PollsConstants.kt
  • stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/composer/attachment/picker/poll/CreatePollViewModel.kt
💤 Files with no reviewable changes (7)
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatTheme.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchInputErrorTest.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/util/PollSwitchItemFactory.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollOptionError.kt
  • stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/poll/PollSwitchItem.kt
  • stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/util/DefaultPollSwitchItemFactoryTest.kt
  • stream-chat-android-compose/detekt-baseline.xml
🚧 Files skipped from review as they are similar to previous changes (2)
  • stream-chat-android-compose/src/main/res/drawable/stream_compose_ic_minus.xml
  • stream-chat-android-compose/src/main/res/values/strings.xml

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

Labels

pr:breaking-change Breaking change pr:improvement Improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant