Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support poll vote/unvote #939

Merged
merged 11 commits into from
Nov 1, 2024
Merged

Support poll vote/unvote #939

merged 11 commits into from
Nov 1, 2024

Conversation

PIG208
Copy link
Member

@PIG208 PIG208 commented Sep 12, 2024

This is stacked on top of #912.

Fixes: #166

@PIG208 PIG208 force-pushed the pr-poll-vote branch 2 times, most recently from 05d75c4 to 30f4ae1 Compare October 3, 2024 21:06
@PIG208 PIG208 marked this pull request as ready for review October 3, 2024 21:07
@PIG208 PIG208 force-pushed the pr-poll-vote branch 2 times, most recently from 1d47050 to ec71e83 Compare October 3, 2024 21:08
@PIG208 PIG208 added the maintainer review PR ready for review by Zulip maintainers label Oct 3, 2024
@PIG208 PIG208 requested a review from chrisbobbe October 3, 2024 21:08
@PIG208 PIG208 changed the title WIP Support poll vote/unvote Support poll vote/unvote Oct 3, 2024
@PIG208

This comment was marked as outdated.

@PIG208 PIG208 removed the maintainer review PR ready for review by Zulip maintainers label Oct 3, 2024
@PIG208 PIG208 force-pushed the pr-poll-vote branch 2 times, most recently from 6de28fa to b0a4dc5 Compare October 7, 2024 23:58
@PIG208
Copy link
Member Author

PIG208 commented Oct 7, 2024

Preview
Screenshot from 2024-10-07 19-55-57 Screenshot from 2024-10-07 19-57-28

@PIG208 PIG208 requested a review from alya October 8, 2024 00:00
@PIG208 PIG208 added the maintainer review PR ready for review by Zulip maintainers label Oct 8, 2024
Copy link
Collaborator

@chrisbobbe chrisbobbe left a comment

Choose a reason for hiding this comment

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

Thanks! Comments below.

Also, I noticed that the web app has a "pressed" style for the button. Do we want to either do that here or make an issue and TODO for it? Like with reactions, I think it helps the user know that the UI has responded to their gesture, in case it takes a while for the event to come through.

I guess my cursor isn't captured in this screenshot :) but you can imagine it there:

image

Comment on lines 14 to 15
// There is also 'zform' for trivia quiz bot, but we currently do not have
// plan to support that.
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit:

  • 'do not have a plan' or
  • 'do not have plans' or
  • 'do not plan'

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm, somehow I perfectly missed all the correct options! 😓

// There is also 'zform' for trivia quiz bot, but we currently do not have
// plan to support that.
'msg_type': RawParameter('widget'),
'content': RawParameter(jsonEncode(content)),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would we get the same result from 'content': content as we do from this, and if so, would it be preferable because it looks simpler?

Copy link
Member Author

Choose a reason for hiding this comment

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

The case of content is a bit peculiar, because the API expects a plain string instead of an object, while the string is expected to be some JSON encoded value.

I think it would be good to mention this in comments.

Copy link
Member

Choose a reason for hiding this comment

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

Is there an actual difference in behavior here from 'content': content?

Remember that parameters on a Zulip API endpoint as a whole are encoded as HTML form data, not as JSON. This is a longstanding gap in our API docs; most recent discussion here:
https://chat.zulip.org/#narrow/channel/138-user-questions/topic/.E2.9C.94.20Slack.20webhook.20incompatible.3F/near/1923677
with link to a previous discussion.

So there's no enclosing JSON object with 'content' as a key, which could then have either a string or an object as a value — there's just a string-to-string key-value map, with content as a key and some string as a value. If that value is itself the JSON-encoding of some object, then that's just the normal way an object appears as a parameter in the Zulip API.

I did a quick check and this passes the newly-added test:

Suggested change
'content': RawParameter(jsonEncode(content)),
'content': content,

options: (options != null)
? options.map((e) => e.text).toList()
options: (optionVoterIdsPairs != null)
? optionVoterIdsPairs.map((e) => e.$1).toList()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh, odd, I guess $1 refers to the first element of the tuple? So it's not zero-indexed.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, records do not have the prettiest syntax.

children: [
ConstrainedBox(
constraints: const BoxConstraints(minWidth: 25).tighten(height: 25),
return Row(
Copy link
Collaborator

Choose a reason for hiding this comment

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

poll [nfc]: Move vote count paddings to a box

This does not visually change the paddings.

This doesn't seem to be true. Here's before/after this change, with message https://chat.zulip.org#narrow/stream/7-test-here/topic/new.20poll.20test/near/1956979 :

Before After
image image

When I open the two images in different browser tabs and switch between them, I see a layout change. Do you reproduce?

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm, I can see that in the screenshots, but not on my Android device.

Copy link
Collaborator

@chrisbobbe chrisbobbe Oct 9, 2024

Choose a reason for hiding this comment

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

When the bottom: 5 padding wraps the whole row (before this commit), instead of just the vote-count rectangle, there will be 5px whitespace below the text (option name + voters' names) even when the text takes more vertical space than the vote-count rectangle.

I think you can reproduce if you make an option with a name so long that it takes two or three lines on your device.

This might be a desired change, but it's not an NFC one :)

Comment on lines 83 to 84
// This is only in effect
// when the vote count has more than 2 digits.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm a little suspicious of a comment like this :) because I don't know if it's true as written for all values of the user's system bold-text and text-size settings. If this needs a comment, maybe it could be something like:

                  // Inner padding preserves whitespace even when the text's
                  // width approaches the button's min-width (e.g. because 
                  // there are three digits).

@alya
Copy link
Collaborator

alya commented Oct 8, 2024

Screenshots and CZO discussion look good to me!

PIG208 added a commit to PIG208/zulip-flutter that referenced this pull request Oct 9, 2024
This would also apply to emoji reaction pills.  This would be an UX
improvement to let the user know that the data is going to be updated.

See also:
  zulip#939 (review)

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this pull request Oct 9, 2024
This would also apply to emoji reaction pills.  This would be an UX
improvement to let the user know that the data is going to be updated.

See also:
  zulip#939 (review)

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this pull request Oct 9, 2024
This would also apply to emoji reaction pills.  This would be an UX
improvement to let the user know that the data is going to be updated.

See also:
  zulip#939 (review)

Signed-off-by: Zixuan James Li <[email protected]>
@PIG208
Copy link
Member Author

PIG208 commented Oct 9, 2024

The "pressed" UX might fit better in a separate PR. I guess we need to have a way to mark some data as "dirty" until an event comes and update it (but there could also be cases where we expect multiple events).

I also noticed that my previous screenshots have a non-default sized text. The 22px font size for the vote count text is actually inadequate. Updated that to 20px with new screenshots:

Updated screenshots
1000014904 1000014902 1000014901

@PIG208 PIG208 requested a review from chrisbobbe October 9, 2024 18:58
@chrisbobbe
Copy link
Collaborator

chrisbobbe commented Oct 9, 2024

The "pressed" UX might fit better in a separate PR. I guess we need to have a way to mark some data as "dirty" until an event comes and update it (but there could also be cases where we expect multiple events).

I was just thinking about highlighting the button when the user's finger is on it; I wasn't thinking about the state between the tap and the event arriving.

—Ah, I guess, what does the web app do? I was assuming it was a simple "pressed" state, but looking closer, I think it might be the more complicated thing where it highlights the button between the tap and the event arrival.

@gnprice
Copy link
Member

gnprice commented Oct 10, 2024

I think it might be the more complicated thing where it highlights the button between the tap and the event arrival.

That more complicated thing sounds like when it has an effect, it'd be liable to make it feel like the button was stuck. (Though I haven't tried to play with this aspect of web's UX.)

I'd be glad to have immediate feedback while the user's finger is there, and perhaps animating back to the resting state over a short fixed duration thereafter like 100ms, while not trying to have any longer-lived "dirty" state. This would make it similar to the existing behavior on the mark-as-read button.

@chrisbobbe
Copy link
Collaborator

chrisbobbe commented Oct 10, 2024

That more complicated thing sounds like when it has an effect, it'd be liable to make it feel like the button was stuck. (Though I haven't tried to play with this aspect of web's UX.)

I agree; let's not do this. I think Vlad likes a scale animation for the "pressed" state, like we did for the mark-as-read button in 791b703.

Then I think #939 (comment) is still pending, about a layout-change commit that should be unmarked NFC. One consequence of the change is that it removes any spacing between two options when the first one's text runs onto multiple lines:

Before After
image image

I don't love that consequence, but it's helped in a later commit that provides 2.5px spacing there (from the verticalPadding). One possible improvement might be to bump that up to 5px by putting a 2.5px margin under the text.

@chrisbobbe
Copy link
Collaborator

Then also, as discussed in the office just now: in the place where we use a fixed height, we'll want a min-height instead, so that it doesn't break with a large system text size setting:

Current revision Changed to min-height
image image

PIG208 added a commit to PIG208/zulip-flutter that referenced this pull request Oct 11, 2024
This would also apply to emoji reaction pills.  This would be an UX
improvement to let the user know that the data is going to be updated.

See also:
  zulip#939 (review)

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this pull request Oct 22, 2024
Visually, this does not change the appearence of the vote count box.

This does not implement local echoing for voting. Instead, we rely on
the submessage events to get the updates after voting.

For accessbility, the touch target is larger than the button.
See also:
  https://chat.zulip.org/#narrow/stream/48-mobile/topic/Poll.20vote.2Funvote.20UI/near/1952724

We add a TODO for pending poll votes visual indicator.  This would also apply
to emoji reaction pills.
See also:
  zulip#939 (review)

Fixes: zulip#166

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this pull request Oct 22, 2024
Visually, this does not change the appearence of the vote count box.

This does not implement local echoing for voting. Instead, we rely on
the submessage events to get the updates after voting.

For accessbility, the touch target is larger than the button.
See also:
  https://chat.zulip.org/#narrow/stream/48-mobile/topic/Poll.20vote.2Funvote.20UI/near/1952724

We add a TODO for pending poll votes visual indicator.  This would also apply
to emoji reaction pills.
See also:
  zulip#939 (review)

Fixes: zulip#166

Signed-off-by: Zixuan James Li <[email protected]>
@PIG208
Copy link
Member Author

PIG208 commented Oct 22, 2024

This PR has been updated. Thanks for the review!

Copy link
Member

@gnprice gnprice left a comment

Choose a reason for hiding this comment

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

Thanks for the revision! Generally this looks good; one question below.

Since this revision changed the layout, please also post updated screenshots.

Comment on lines -72 to -73
return Padding(
padding: const EdgeInsets.only(bottom: 5),
Copy link
Member

Choose a reason for hiding this comment

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

poll: Move vote count paddings inside children of Row

It looks like in this revision, this commit actually moves the padding only inside the first child, and drops the padding from the second one.

This preserves most of the visuals. Except that when the vote count
box is shorter than the voter names text, the padding between rows
is gone.

That seems undesirable. What if we include padding on both children, like in the previous revision?

I think this change in this revision may have been in response to this thread:
#939 (comment)
but I don't really understand the motivation for removing the padding from the voter names.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks! Pulled that back and edited the comment. I removed it previously because I thought it was somewhat a hacky workaround, which could be confusing.

Copy link
Member

Choose a reason for hiding this comment

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

Cool. Yeah, I see it as putting the same padding on each sibling — which seems like a normal reasonable thing to do, not anything hacky.

PIG208 added a commit to PIG208/zulip-flutter that referenced this pull request Oct 25, 2024
Visually, this does not change the appearence of the vote count box.

This does not implement local echoing for voting. Instead, we rely on
the submessage events to get the updates after voting.

For accessbility, the touch target is larger than the button.
See also:
  https://chat.zulip.org/#narrow/stream/48-mobile/topic/Poll.20vote.2Funvote.20UI/near/1952724

We add a TODO for pending poll votes visual indicator.  This would also apply
to emoji reaction pills.
See also:
  zulip#939 (review)

Fixes: zulip#166

Signed-off-by: Zixuan James Li <[email protected]>
Copy link
Member

@gnprice gnprice left a comment

Choose a reason for hiding this comment

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

Great, thanks for changing that back.

Small comments below — most of them about a follow-up in that same area.

Comment on lines -72 to -73
return Padding(
padding: const EdgeInsets.only(bottom: 5),
Copy link
Member

Choose a reason for hiding this comment

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

Cool. Yeah, I see it as putting the same padding on each sibling — which seems like a normal reasonable thing to do, not anything hacky.

Comment on lines 118 to 123
child: Padding(
// This padding and the bottom padding on the vote count box
// extends the row by the same extent. This ensures that there
// still will be consistent spacing between rows, when the text
// takes more vertical space than the vote count box.
padding: const EdgeInsets.only(bottom: verticalPadding),
Copy link
Member

Choose a reason for hiding this comment

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

Why is this padded only on the bottom, while the buttons are padded top and bottom?

Comment on lines 138 to 141
Padding(
// `verticalPadding` out of 6 logical pixels come from the first
// option row.
padding: const EdgeInsets.only(bottom: 6 - verticalPadding),
Copy link
Member

Choose a reason for hiding this comment

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

This reasoning assumes that the first option row has some top padding. But in this version that only holds if the button is taller than the text, right?

Copy link
Member

Choose a reason for hiding this comment

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

Ah, I guess if the text is long, then there's still top padding because CrossAxisAlignment.baseline means the option text starts at the same level as the count and expands down from there, and so the button still extends further upward from the baseline than the text does.

Still: the much simpler way for the reader to reach the conclusion that there's always top padding on an option row would be if both children of the row had the same top padding.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, I guess if the text is long, then there's still top padding because CrossAxisAlignment.baseline means the option text starts at the same level as the count and expands down from there, and so the button still extends further upward from the baseline than the text does.

Yeah, exactly. I've made them symmetric in the new revision.

Comment on lines 144 to 146
Padding(
// This is consistent with the option items' top padding.
padding: const EdgeInsets.only(top: verticalPadding),
Copy link
Member

Choose a reason for hiding this comment

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

Similarly here.

I think this probably all becomes cleaner to think about if the text gains verticalPadding of top padding.

Comment on lines 4 to 6
/// https://zulip.readthedocs.io/en/latest/subsystems/widgets.html#polls-todo-lists-and-games
Future<void> sendSubmessage(ApiConnection connection, {
Copy link
Member

Choose a reason for hiding this comment

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

This dartdoc should also link to the zulip-mobile implementation, given that that's one of the sources we relied on in writing this implementation (as the commit message says).

The route is not documented in the Zulip API Documentation.

Instead, we refer to the zulip-mobile implementation and
https://zulip.readthedocs.io/en/latest/subsystems/widgets.html#polls-todo-lists-and-games.

Signed-off-by: Zixuan James Li <[email protected]>
The `preparePollMessage` helper was only using `PollOption` for
convenience.  It doesn't actually need the `PollOption` instances.
This allows us to make changes to `PollOption` more freely.

Signed-off-by: Zixuan James Li <[email protected]>
This allows us to lookup the key that corresponds to the PollOption
without referencing back the map.

Signed-off-by: Zixuan James Li <[email protected]>
This makes it easier to follow font sizes of UI elements in this widget.

We leave textStyleVoterNames as-is because we never need to override
the font size.

Signed-off-by: Zixuan James Li <[email protected]>
On devices with non-default text scaling, the fixed size vote count box
might be too short to fit in the text.  We should only set the min
height to fix that.

Signed-off-by: Zixuan James Li <[email protected]>
We already center the text with `Center`, which is preferred because it
also centers vertically.

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this pull request Oct 28, 2024
Visually, this does not change the appearence of the vote count box.

This does not implement local echoing for voting. Instead, we rely on
the submessage events to get the updates after voting.

For accessbility, the touch target is larger than the button.
See also:
  https://chat.zulip.org/#narrow/stream/48-mobile/topic/Poll.20vote.2Funvote.20UI/near/1952724

We add a TODO for pending poll votes visual indicator.  This would also apply
to emoji reaction pills.
See also:
  zulip#939 (review)

Fixes: zulip#166

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this pull request Oct 28, 2024
Visually, this does not change the appearence of the vote count box.

This does not implement local echoing for voting. Instead, we rely on
the submessage events to get the updates after voting.

For accessbility, the touch target is larger than the button.
See also:
  https://chat.zulip.org/#narrow/stream/48-mobile/topic/Poll.20vote.2Funvote.20UI/near/1952724

We add a TODO for pending poll votes visual indicator.  This would also apply
to emoji reaction pills.
See also:
  zulip#939 (review)

Fixes: zulip#166

Signed-off-by: Zixuan James Li <[email protected]>
@PIG208
Copy link
Member Author

PIG208 commented Oct 28, 2024

Pushed a new revision. Thanks for the review!

  • Now we use vertically symmetric padding for all the option items, and limit the one-sided paddings.
  • This also fixed an issue with the "This poll has no options yet" text where the bottom padding is missing.
  • I added 5 - verticalPadding to the entire poll widget so that there is still 5px space after it.
before after
1000015159 1000015158

Copy link
Member

@gnprice gnprice left a comment

Choose a reason for hiding this comment

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

Thanks for the revision! Glad to have that layout issue fixed — and I think the layout logic all makes sense to me now. Just a few style comments below.

Comment on lines 148 to 149
Padding(
// This is consistent with the option rows' padding.
Copy link
Member

Choose a reason for hiding this comment

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

This change makes this commit no longer NFC, right?
ceca4ce poll [nfc]: Move vote count paddings inside children of Row

It's also not part of what that summary describes. So I think it should just become a separate commit, fixing that layout bug you noted.

Comment on lines 142 to 146
Padding(
// `verticalPadding` out of 6 logical pixels
// come from the first option row.
padding: const EdgeInsets.only(bottom: 6 - verticalPadding),
child: question),
Copy link
Member

Choose a reason for hiding this comment

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

nit: this is a bit simpler to express with a SizedBox spacer:

Suggested change
Padding(
// `verticalPadding` out of 6 logical pixels
// come from the first option row.
padding: const EdgeInsets.only(bottom: 6 - verticalPadding),
child: question),
question,
// `verticalPadding` out of 6px come from the first option row.
const SizedBox(height: 6 - verticalPadding),

Comment on lines 135 to 138
return Padding(
// `verticalPadding` out of 5 logical pixels
// come from the last option row.
padding: const EdgeInsets.only(bottom: 5 - verticalPadding),
Copy link
Member

Choose a reason for hiding this comment

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

Then similarly this padding can be expressed as a spacer at the end of the column's children. I think that makes it significantly clearer what's going on, because it keeps things in a consistent order.

It makes it easier to adjust the size of the vote count box touch
target later.

This preserves the visuals. In particular, we add bottom paddings
to both the vote count box and the option/voters text to ensure
that there is always 5px between option rows, as it was before.

The end padding is equivalent to the spacing previously specified on
the Row; the bottom padding is equivalent to the padding specified on
the outer (now removed) Padding.  The ConstrainedBox is expanded
because it now also contains the paddings.

Signed-off-by: Zixuan James Li <[email protected]>
Previously, the 5px bottom padding only existed when there were option
rows. This padding should be applied to the placeholder text as well.

Signed-off-by: Zixuan James Li <[email protected]>
PIG208 added a commit to PIG208/zulip-flutter that referenced this pull request Oct 29, 2024
Visually, this does not change the appearence of the vote count box.

This does not implement local echoing for voting. Instead, we rely on
the submessage events to get the updates after voting.

For accessbility, the touch target is larger than the button.
See also:
  https://chat.zulip.org/#narrow/stream/48-mobile/topic/Poll.20vote.2Funvote.20UI/near/1952724

We add a TODO for pending poll votes visual indicator.  This would also apply
to emoji reaction pills.
See also:
  zulip#939 (review)

Fixes: zulip#166

Signed-off-by: Zixuan James Li <[email protected]>
@PIG208
Copy link
Member Author

PIG208 commented Oct 29, 2024

Thanks! The PR has been updated.

Previously, there were only bottom and end paddings; we redistribute
the vertical paddings so the vote count box is padded on both sides.

The end padding remains 5px because we want to keep the options aligned
to the start with the surrounding messages.

This change also affects the poll question, where 2.5px of space gets
moved to the first option row.

Similarly, the end of the poll was previously padded by the last poll
option alone. Now 2.5px of space gets moved to the `Padding` wrapping
the entire `Column` of the poll.

Signed-off-by: Zixuan James Li <[email protected]>
Visually, this does not change the appearence of the vote count box.

This does not implement local echoing for voting. Instead, we rely on
the submessage events to get the updates after voting.

For accessbility, the touch target is larger than the button.
See also:
  https://chat.zulip.org/#narrow/stream/48-mobile/topic/Poll.20vote.2Funvote.20UI/near/1952724

We add a TODO for pending poll votes visual indicator.  This would also apply
to emoji reaction pills.
See also:
  zulip#939 (review)

Fixes: zulip#166

Signed-off-by: Zixuan James Li <[email protected]>
@gnprice
Copy link
Member

gnprice commented Nov 1, 2024

Thanks! Looks good now — merging, with two tweaks:

-    poll: Enlarge and vetically center vote count box
+    poll: Enlarge and vertically center vote count box


-+        // `verticalPadding` out of 6px come from the first option row.
++        // `verticalPadding` out of 6px comes from the first option row.

(I know the latter comes from my suggestion above; rereading, I'd incompletely edited it from the previous version.)

@gnprice gnprice merged commit 9fde534 into zulip:main Nov 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
integration review Added by maintainers when PR may be ready for integration
Projects
None yet
Development

Successfully merging this pull request may close these issues.

polls: Vote and unvote on options
4 participants