Skip to content

Conversation

@andremion
Copy link
Contributor

@andremion andremion commented Dec 15, 2025

🎯 Goal

Fix poll results dialogs showing only 10 votes when polls have more votes. The /channels/{type}/{id}/query endpoint returns a limited number of latest votes in latest_votes_by_option, while the total vote_count can be higher.

Closes https://linear.app/stream/issue/AND-953

🛠 Implementation details

  • Added PollResultsViewController in ui-common to manage poll results state and pagination
  • Implemented pagination using /polls/{poll_id}/votes endpoint (page size: 25, same as iOS)
  • Added PollResultsViewModel for both Compose and XML SDKs
  • Refactored PollViewResultDialog (Compose) to use ViewModel with ModalBottomSheet for proper window insets
  • Refactored PollResultsDialogFragment (XML) with NestedScrollViewPaginationHelper for pagination
  • Added loading states, error handling, and automatic pagination on scroll
  • Moved poll option sorting and winner calculation to the controller
  • Added reference counting for poll data to handle configuration changes

🎨 UI Changes

XML Before XML After
xml_before.webm
xml_after.webm
Compose Before Compose After
compose_before.webm
compose_after.webm

🧪 Testing

  • Unit tests
  • Manual testing with polls containing 10+ votes in both SDKs
  • Verified configuration changes (screen rotation) don't lose poll data
  • Updated snapshot tests for Compose UI

… for displaying poll results. It handles fetching poll votes with pagination.

The following new classes have been added to support this controller:
- `PollResultsViewState` to represent the different states of the view (Loading, Content, Error).
- `PollResultsViewAction` for user actions like requesting to load more votes.
- `PollResultsViewEvent` for events from the controller, such as load errors.

Unit tests for `PollResultsViewController` have also been added to ensure its correctness.
…g ModalBottomSheet, which provides similar and improved animation, without the padding issue.
The `PollResultsViewState` is simplified from a sealed interface with `Loading`, `Content`, and `Error` states to a single data class. This change streamlines state management by using boolean flags like `isLoading` and `isLoadingMore`.

Error handling is now managed through a separate event channel, and the query limit for fetching poll votes has been increased.
The `PollResultsViewState` is simplified from a sealed interface with `Loading`, `Content`, and `Error` states to a single data class. This change streamlines state management by using boolean flags like `isLoading` and `isLoadingMore`.

Error handling is now managed through a separate event channel, and the query limit for fetching poll votes has been increased.
This change refactors how the `Poll` object is passed to the `PollResultsDialogFragment` to prevent crashes during process recreation.

The `Poll` object is now stored in a static map within the companion object, and its ID is passed through the fragment's arguments. Reference counting is used to manage the lifecycle of the poll object in the map, ensuring it's cleared when no longer needed. This avoids serializing the large `Poll` object directly into the arguments bundle.
@github-actions
Copy link
Contributor

github-actions bot commented Dec 15, 2025

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 5.25 MB 5.25 MB 0.00 MB 🟢
stream-chat-android-offline 5.48 MB 5.48 MB 0.00 MB 🟢
stream-chat-android-ui-components 10.60 MB 10.61 MB 0.01 MB 🟢
stream-chat-android-compose 12.81 MB 12.82 MB 0.01 MB 🟢

@andremion andremion changed the title Fix Poll results dialog Fix: Poll Results Dialog Shows All Votes with Pagination Support Dec 15, 2025
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
78.4% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@andremion andremion marked this pull request as ready for review December 15, 2025 16:20
@andremion andremion requested a review from a team as a code owner December 15, 2025 16:20
@andremion andremion added compose Jetpack Compose ui-components labels Dec 15, 2025
@andremion andremion changed the title Fix: Poll Results Dialog Shows All Votes with Pagination Support Make Poll Results Dialog Shows All Votes with Pagination Support Dec 15, 2025

item { Spacer(modifier = Modifier.height(16.dp)) }
if (state.isLoading || state.isLoadingMore) {
LoadingIndicator(modifier = Modifier.fillMaxSize())
Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't this be shown over the list of votes? Is that intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. It is shown for the initial load and the pagination loads.
The idea was not to show only the loading UI and block the user, since we already have an initial poll object (which contains 10 max votes).

Copy link
Contributor

Choose a reason for hiding this comment

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

Bit strange if you ask me... Maybe this is something to bring up for the upcoming design refresh?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure.
What UX would you suggest?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't really have any good suggestions... Based on how the pagination works in this case, we cannot really know where to show a loading placeholder, so any assumptions could be wrong.

@VelikovPetar
Copy link
Contributor

I think the wrong ticket is linked here, should be: AND-953

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.

3 participants