-
Notifications
You must be signed in to change notification settings - Fork 171
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
Conversation
05d75c4
to
30f4ae1
Compare
1d47050
to
ec71e83
Compare
This comment was marked as outdated.
This comment was marked as outdated.
6de28fa
to
b0a4dc5
Compare
There was a problem hiding this 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:
lib/api/route/submessage.dart
Outdated
// There is also 'zform' for trivia quiz bot, but we currently do not have | ||
// plan to support that. |
There was a problem hiding this comment.
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'
There was a problem hiding this comment.
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! 😓
lib/api/route/submessage.dart
Outdated
// 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)), |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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:
'content': RawParameter(jsonEncode(content)), | |
'content': content, |
options: (options != null) | ||
? options.map((e) => e.text).toList() | ||
options: (optionVoterIdsPairs != null) | ||
? optionVoterIdsPairs.map((e) => e.$1).toList() |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
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 |
---|---|
When I open the two images in different browser tabs and switch between them, I see a layout change. Do you reproduce?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 :)
lib/widgets/poll.dart
Outdated
// This is only in effect | ||
// when the vote count has more than 2 digits. |
There was a problem hiding this comment.
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).
Screenshots and CZO discussion look good to me! |
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]>
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]>
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]>
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: |
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. |
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. |
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:
I don't love that consequence, but it's helped in a later commit that provides 2.5px spacing there (from the |
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]>
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]>
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]>
This PR has been updated. Thanks for the review! |
There was a problem hiding this 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.
return Padding( | ||
padding: const EdgeInsets.only(bottom: 5), |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
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]>
There was a problem hiding this 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.
return Padding( | ||
padding: const EdgeInsets.only(bottom: 5), |
There was a problem hiding this comment.
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.
lib/widgets/poll.dart
Outdated
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), |
There was a problem hiding this comment.
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?
lib/widgets/poll.dart
Outdated
Padding( | ||
// `verticalPadding` out of 6 logical pixels come from the first | ||
// option row. | ||
padding: const EdgeInsets.only(bottom: 6 - verticalPadding), |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
lib/widgets/poll.dart
Outdated
Padding( | ||
// This is consistent with the option items' top padding. | ||
padding: const EdgeInsets.only(top: verticalPadding), |
There was a problem hiding this comment.
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.
lib/api/route/submessage.dart
Outdated
/// https://zulip.readthedocs.io/en/latest/subsystems/widgets.html#polls-todo-lists-and-games | ||
Future<void> sendSubmessage(ApiConnection connection, { |
There was a problem hiding this comment.
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]>
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]>
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]>
There was a problem hiding this 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.
lib/widgets/poll.dart
Outdated
Padding( | ||
// This is consistent with the option rows' padding. |
There was a problem hiding this comment.
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.
lib/widgets/poll.dart
Outdated
Padding( | ||
// `verticalPadding` out of 6 logical pixels | ||
// come from the first option row. | ||
padding: const EdgeInsets.only(bottom: 6 - verticalPadding), | ||
child: question), |
There was a problem hiding this comment.
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:
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), |
lib/widgets/poll.dart
Outdated
return Padding( | ||
// `verticalPadding` out of 5 logical pixels | ||
// come from the last option row. | ||
padding: const EdgeInsets.only(bottom: 5 - verticalPadding), |
There was a problem hiding this comment.
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]>
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]>
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]>
Thanks! Looks good now — merging, with two tweaks:
(I know the latter comes from my suggestion above; rereading, I'd incompletely edited it from the previous version.) |
This is stacked on top of #912.Fixes: #166