-
Notifications
You must be signed in to change notification settings - Fork 310
msglist: Show message reactions; support reacting (with 👍, or to join in others' reactions) #410
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
Conversation
a6a0fee
to
ecce64c
Compare
Oh, I've noticed a subtle bug in the model code. When you have two message lists open, and a new-message event arrives, we add the same Here's a recipe for reproducing one symptom:
In step 9, the |
Interesting, yeah. I think we can let that bug not block merging this, and handle it later. The fix will probably involve having a central map of messages, akin to state.messages in zulip-mobile. |
ecce64c
to
a3a5f5a
Compare
Just pushed a revision with a quick add-thumbs-up button in the message action sheet, which we'll plan to replace later: (And so updated the PR description to say that, for #125, this is a full fix instead of a partial one.) ![]() |
(Also I'll need to write some tests; I guess I should mark as a draft because of 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.
Thanks! Great to see this. Here's a review from without having yet fetched your revision today. Generally all small comments, but one exciting wrinkle when it comes to the font layout.
import 'store.dart'; | ||
import 'text.dart'; | ||
|
||
class ReactionChipsList extends StatelessWidget { |
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.
And also support:
- removing a reaction you've already made, and
- joining in on existing reactions that other people have made.
It leaves out one part of #125, for now:
- joining in on an existing reaction other people have made
I think the latter item means to say adding a thumbs-up reaction 🙂
lib/widgets/emoji_reaction.dart
Outdated
final int messageId; | ||
final Reactions reactions; | ||
|
||
const ReactionChipsList({ | ||
super.key, | ||
required this.messageId, | ||
required this.reactions, | ||
}); |
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: constructor before fields
(the exception to that is for "data"-style classes, which generally includes what's in lib/api/ but which doesn't include widgets)
lib/widgets/emoji_reaction.dart
Outdated
return Tooltip( | ||
excludeFromSemantics: true, // TODO: Semantics with eg "Reaction: <emoji name>; you and N others: <names>" | ||
message: emojiName, | ||
child: Material( |
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: indentation
lib/widgets/emoji_reaction.dart
Outdated
child: (() { | ||
if (emojiset == Emojiset.text) { | ||
return _TextEmoji(emojiName: emojiName, selected: selfVoted); | ||
} | ||
switch (reactionType) { | ||
case ReactionType.unicodeEmoji: |
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 is probably easiest to read as a local variable:
final Widget emoji;
if (emojiset == Emojiset.text) {
emoji = _TextEmoji(emojiName: emojiName, selected: selfVoted);
} else {
switch (reactionType) {
// …
lib/widgets/emoji_reaction.dart
Outdated
@override | ||
Widget build(BuildContext context) { | ||
final parsed = tryParseEmojiCodeToUnicode(emojiCode); | ||
if (parsed == null) { |
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.
if (parsed == null) { | |
if (parsed == null) { // TODO(log) |
This shouldn't actually be possible.
lib/widgets/emoji_reaction.dart
Outdated
final doNotAnimate = MediaQuery.of(context).disableAnimations | ||
|| PlatformDispatcher.instance.accessibilityFeatures.reduceMotion; |
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 interesting — are these two different settings?
In any event the PlatformDispatcher.instance
should instead be WidgetsBinding.instance.platformDispatcher
. See docs on PlatformDispatcher and PlatformDispatcher.instance.
But then even the binding is a global thing, whereas MediaQuery has the job of exposing much of that information in a more widgets-oriented way. Does MediaQuery not expose the latter setting?
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.
Yes, these are two different settings. See AccessibilityFeatures.reduceMotion
and AccessibilityFeatures.disableAnimations
: https://api.flutter.dev/flutter/dart-ui/AccessibilityFeatures-class.html
It says "reduce motion" is an iOS-only setting, though. Probably best/safest to only check it on iOS; I'll do that.
"Disable animations" is exposed on MediaQueryData
: https://api.flutter.dev/flutter/widgets/MediaQueryData/disableAnimations.html
But "reduce motion" is not. There is an issue to expose it there (flutter/flutter#65874), but it looks like something else might be done instead, like it might be exposed on a new inherited widget.
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, thanks.
I think "reduce motion" probably shouldn't control this. Here's what looks to be Apple dev docs for it:
https://developer.apple.com/documentation/swiftui/environmentvalues/accessibilityreducemotion
If this property’s value is true, UI should avoid large animations, especially those that simulate the third dimension.
And the user-facing description, from the screenshot in that upstream image, is:
Reduce the motion of the user interface, including the parallax effect of icons.
So that sounds like a different type of thing from this.
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.
We discussed this further in our call today, and it looks like disableAnimations
actually never gets set on iOS. Given that, we should probably consult reduceMotion
after all (like the current revision does) so that the user has some way to ask the animations to stop.
Then recent versions of iOS (iOS 17+, so new this year) do have a more closely relevant setting:
https://developer.apple.com/documentation/swiftui/environmentvalues/accessibilityplayanimatedimages
which is documented for users at
https://support.apple.com/guide/iphone/reduce-onscreen-motion-iph0b691d3ed/ios
as:
Auto-Play Animated Images: […] (When on, rapid animated images and moving elements such as GIFs in Messages and Safari play automatically.)
So there should be a Flutter issue upstream to provide that value, either by having it control disableAnimations
or by adding a new separate field on AccessibilityFeatures
.
If there's such an issue already, we can link to it in a comment here. If not, we can leave a TODO comment for ourselves to file that issue — though actually filing it would be a task for after Beta 1.
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. Thanks for writing that down!
lib/widgets/emoji_reaction.dart
Outdated
final doNotAnimate = MediaQuery.of(context).disableAnimations | ||
|| PlatformDispatcher.instance.accessibilityFeatures.reduceMotion; | ||
|
||
String src; |
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.
String src; | |
final String src; |
That way the compiler verifies that it's only ever set once.
lib/widgets/emoji_reaction.dart
Outdated
final store = PerAccountStoreWidget.of(context); | ||
|
||
// Some people really dislike animated emoji. | ||
final doNotAnimate = MediaQuery.of(context).disableAnimations |
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.
final doNotAnimate = MediaQuery.of(context).disableAnimations | |
final doNotAnimate = MediaQuery.disableAnimationsOf(context) |
(see its doc)
lib/widgets/emoji_reaction.dart
Outdated
return SizedBox( | ||
width: textScaler.scale(17), | ||
child: Text( | ||
style: const TextStyle(fontSize: 17), | ||
strutStyle: const StrutStyle(fontSize: 17, forceStrutHeight: true), | ||
parsed)); |
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.
Fun. So for me on a Pixel, this gives different results from what you're seeing on iOS. Specifically here it is on a message where I've added a bunch of the same reactions:
The Unicode emoji there are crowding the counts. That's because, the inspector tells me, the glyphs are overflowing wider than the 17px of the box they're in. The height is 20px, and if I remove the SizedBox, the layout width is too, reflecting the width they already have visually.
So it seems that for the Noto emoji font (which is what this device has for a system emoji font), a font size of 17 gets glyphs with an actual size of 20px.
From a binary search, if I set the font size to 14.5, then the actual resulting size is 17.0px. If I do that and also take out that one pixel of left padding to match web, then the result is:
which looks a lot better aligned.
@@ -118,4 +118,1 @@ class ReactionChip extends StatelessWidget {
- //
- // Separately, web has 1px less than this on the left, but that
- // asymmetry doesn't seem to help us.
- padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 2),
+ padding: const EdgeInsets.fromLTRB(4, 2, 5, 2),
@@ -179,9 +176,10 @@ class _UnicodeEmoji extends StatelessWidget {
return _TextEmoji(emojiName: emojiName, selected: selected);
}
final textScaler = MediaQuery.textScalerOf(context);
+ const fontSize = 14.5;
return SizedBox(
width: textScaler.scale(17),
child: Text(
- style: const TextStyle(fontSize: 17),
- strutStyle: const StrutStyle(fontSize: 17, forceStrutHeight: true),
+ style: const TextStyle(fontSize: fontSize),
+ strutStyle: const StrutStyle(fontSize: fontSize, forceStrutHeight: true),
parsed));
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 can partly be seen as a downstream consequence of not bundling an emoji font.
Maybe the right approach to keep things moving is:
- Have a
defaultTargetPlatform
check that makes a couple of things different here between iOS and Android. - On iOS, find whatever value goes instead of 14.5 that gets a size of 17 with Apple's emoji font.
- On Android, use that value of 14.5 that gets a size of 17 with the Noto emoji font.
- That will make it work exactly as desired on iOS devices and Pixel devices. It might look a little odd on other Android devices — not sure how much.
- And then as a followup issue, we'll go back to bundling Noto Color Emoji, but only on non-Apple platforms because Apple platforms aren't compatible with it. Then this will work exactly as desired on all devices.
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. Thanks for that investigation and proposed way forward!
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.
Things are different on iOS—a font size of 17 gives an emoji that looks (to me) approximately 17px square…but the Text
takes 20px height by 21.3px width, when not constrained by the SizedBox
. And the emoji doesn't look centered in the space occupied by the Text
.
I think this is flutter/flutter#119623 and flutter/flutter#28894. I'm going to try this workaround for it (which I see you've 👍-reacted before): flutter/flutter#28894 (comment)

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 going to try this workaround for it (which I see you've 👍-reacted before): […]
Actually I'm not very excited about doing this; I'll try something 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.
I'm going to try this workaround for it (which I see you've 👍-reacted before): flutter/flutter#28894 (comment)
Actually I'm not very excited about doing this; I'll try something simpler.
Yeah, I think my 👍 there wasn't about the substance of the workaround so much as about returning to on-topic discussion.
I agree that thread looks highly relevant. Here's the key piece of investigation:
flutter/flutter#28894 (comment)
In short I think the behavior we're seeing on Android, where font size 17 makes a glyph that's actually 20px, is the intended behavior on both Android and iOS, because it's what users like for emoji in the middle of text. And Flutter currently isn't getting that behavior on iOS because the way Apple accomplishes it is some kind of hack that isn't in their core text-handling libraries.
lib/widgets/emoji_reaction.dart
Outdated
final resolved = store.account.realmUrl.resolveUri(parsedSrc); | ||
|
||
// Unicode emoji get scaled; it would look weird if image emoji didn't. | ||
final size = MediaQuery.textScalerOf(context).scale(17); |
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.
It'd be good for this 17 to be a named constant that's shared with the other 17s that are meant to equal it, in _UnicodeEmoji and _TextEmoji.
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.
OK, and small comments on the action-sheet item. That UI for it looks good to me!
lib/widgets/action_sheet.dart
Outdated
?.aggregated.any((reactionWithVotes) => | ||
reactionWithVotes.emojiCode == '1f44d' |
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.
Should check reactionType
before emojiCode
, as the latter is namespaced by the former.
lib/widgets/action_sheet.dart
Outdated
|
||
@override | ||
String label(ZulipLocalizations zulipLocalizations) { | ||
return 'React with 👍'; // skip translation for now |
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.
return 'React with 👍'; // skip translation for now | |
return 'React with 👍'; // TODO(i18n) skip translation for now |
I'd like this spot to come up in a grep for places that need i18n, even if we don't end up acting on this one in particular before we replace the code.
lib/widgets/action_sheet.dart
Outdated
// This button is very temporary, to complete #125 before we have a way to | ||
// choose an arbitrary reaction (#388). So, skipping tests and i18n. | ||
class AddThumbsUpButton extends MessageActionSheetMenuItemButton { |
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 think it wouldn't take much work to write just a test or two for this, so it's worth doing that. The main thing for a test is: tap the icon, check that we made an appropriate API request.
A bonus test would be: prepare an error response, tap the icon, check that there's an error dialog (and so we didn't just crash).
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.
Can drop the "skipping tests" part now :-)
a3a5f5a
to
00d42b4
Compare
Thanks for the review! Revision pushed. It still needs tests for the reaction-chips UI. This time I've also included screenshots from the office Android device; see below. This device is old, and it's not using Noto Color Emoji, so it'll look different after #404. But I think the layout turns out OK anyway.
|
lib/widgets/emoji_reaction.dart
Outdated
if (defaultTargetPlatform != TargetPlatform.iOS | ||
&& defaultTargetPlatform != TargetPlatform.macOS) { |
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.
Let's use a switch — that way if another value is added (perhaps they bow to Apple's naming and make a separate TargetPlatform.iPadOS
?!?), we get exhaustiveness checking to make sure we choose which behavior the new value should get.
lib/widgets/emoji_reaction.dart
Outdated
// TODO(#404) Actually bundle Noto Color Emoji with the app. Some newer Android | ||
// phones seem to use Noto Color Emoji automatically, but it might not be | ||
// universal, and at least the office Android device (which is old) doesn't. |
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, this definitely isn't universal among Android devices, even new ones. In particular Samsung has their own emoji font.
See for example Emojipedia's list of glyphs for a random emoji:
https://emojipedia.org/moose#designs
They do say of Noto Color Emoji:
Default emoji set for Android devices created by Google and used on devices by Google, Xiaomi, Oppo, Huawei, Sony, and many others.
lib/widgets/emoji_reaction.dart
Outdated
final doNotAnimate = MediaQuery.of(context).disableAnimations | ||
|| PlatformDispatcher.instance.accessibilityFeatures.reduceMotion; |
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, thanks.
I think "reduce motion" probably shouldn't control this. Here's what looks to be Apple dev docs for it:
https://developer.apple.com/documentation/swiftui/environmentvalues/accessibilityreducemotion
If this property’s value is true, UI should avoid large animations, especially those that simulate the third dimension.
And the user-facing description, from the screenshot in that upstream image, is:
Reduce the motion of the user interface, including the parallax effect of icons.
So that sounds like a different type of thing from this.
test/widgets/action_sheet_test.dart
Outdated
TestZulipBinding.ensureInitialized(); | ||
TestWidgetsFlutterBinding.ensureInitialized(); |
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.
These only need to be called once, at the top of main
.
lib/widgets/emoji_reaction.dart
Outdated
final String emojiName; | ||
final bool selected; | ||
|
||
const _TextEmoji({required this.emojiName, required this.selected}); |
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: constructor before fields
lib/widgets/emoji_reaction.dart
Outdated
final doNotAnimate = MediaQuery.of(context).disableAnimations | ||
|| PlatformDispatcher.instance.accessibilityFeatures.reduceMotion; |
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.
We discussed this further in our call today, and it looks like disableAnimations
actually never gets set on iOS. Given that, we should probably consult reduceMotion
after all (like the current revision does) so that the user has some way to ask the animations to stop.
Then recent versions of iOS (iOS 17+, so new this year) do have a more closely relevant setting:
https://developer.apple.com/documentation/swiftui/environmentvalues/accessibilityplayanimatedimages
which is documented for users at
https://support.apple.com/guide/iphone/reduce-onscreen-motion-iph0b691d3ed/ios
as:
Auto-Play Animated Images: […] (When on, rapid animated images and moving elements such as GIFs in Messages and Safari play automatically.)
So there should be a Flutter issue upstream to provide that value, either by having it control disableAnimations
or by adding a new separate field on AccessibilityFeatures
.
If there's such an issue already, we can link to it in a comment here. If not, we can leave a TODO comment for ourselves to file that issue — though actually filing it would be a task for after Beta 1.
Thanks for the revision! This looks great. Small comments above, and otherwise it just needs a few tests for the UI. As we discussed in our call, those tests can be kept simple; it's OK if they don't fully exercise all the things this code takes care of, when those seem like they'd be complicated to test. (Like the One key useful step for the tests is to just build the UI in situations with long names and such, to force it to overflow one line, and check that it doesn't crash. Because the tests run with debug assertions, that will also have the effect of checking that it doesn't hit buggy layout conditions like having a Row or Column widget overflow. |
These calls only need to happen once, at the top of `main`: zulip#410 (comment)
00d42b4
to
c84040a
Compare
These calls only need to happen once, at the top of `main`: zulip#410 (comment)
c84040a
to
a3d0070
Compare
Revision pushed, with some smoke tests this time. So, un-marking as a draft! 🎉 I did make a change that affects
This mostly leaves more common cases unchanged:
but I should point out that as a consequence of the implementation, the label text will linebreak a little bit sooner than is strictly necessary, when the emoji part is square (which for most people it always is): ![]() |
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! This all looks good. The one high-level comment I have is that this is a more intense set of tests than I had in mind — good to have but probably something quicker to write would have been best given the pair of upcoming releases.
Small comments below, almost all on the tests. (And for the commit that's also #425, I reviewed it there.)
lib/widgets/emoji_reaction.dart
Outdated
child: LayoutBuilder( | ||
builder: (context, constraints) { | ||
final maxRowWidth = constraints.maxWidth; | ||
// To give text emojis some room so they need fewer line breaks | ||
// when the label is long | ||
final maxLabelWidth = (maxRowWidth - 6) * 0.75; // 6 is 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.
Hmm interesting.
I have an intuition that LayoutBuilder
potentially comes at a performance cost. It has the flavor of inverting layers — it's a way of re-entering the build phase while in the layout phase.
But I don't see a warning of any kind in its docs:
https://api.flutter.dev/flutter/widgets/LayoutBuilder-class.html
so maybe there's nothing to worry about. I guess we can revisit this in the future if we see evidence of a problem.
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; hmm. Makes sense.
lib/widgets/emoji_reaction.dart
Outdated
// To give text emojis some room so they need fewer line breaks | ||
// when the label is long | ||
final maxLabelWidth = (maxRowWidth - 6) * 0.75; // 6 is 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.
but I should point out that as a consequence of the implementation, the label text will linebreak a little bit sooner than is strictly necessary, when the emoji part is square (which for most people it always is)
Yeah. Hmm I see, and at this point we don't actually know whether we'll end up showing a text emoji, because we use those as fallbacks for error conditions. Including an image not loading, which is something we learn especially late.
Let's file a quick followup issue for this (quick in the effort of filing, not of resolving the issue), milestoned post-launch. And then we'll see if it bugs people; if not, we can just leave it this way indefinitely. If people do complain, the issue will be useful by saving us the effort of debugging to diagnose it or of rediscovering why it's not easy to fix (and what other cases the easy fixes would break).
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.
Sure, makes sense. -> #433
void main() { | ||
group('ReactionChipsList', () { | ||
TestZulipBinding.ensureInitialized(); | ||
|
||
late PerAccountStore store; |
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: put binding ensureInitialized
at top of main:
void main() { | |
group('ReactionChipsList', () { | |
TestZulipBinding.ensureInitialized(); | |
late PerAccountStore store; | |
void main() { | |
TestZulipBinding.ensureInitialized(); | |
group('ReactionChipsList', () { | |
late PerAccountStore store; |
That's how it effectively behaves anyway — because it's outside of any test
call, it's running regardless of which subset of tests are selected by --name
or the like — so might as well have the code reflect that.
addTearDown(() { | ||
tester.platformDispatcher.clearTextScaleFactorTestValue(); | ||
}); |
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: can simplify slightly by using a tear-off:
addTearDown(() { | |
tester.platformDispatcher.clearTextScaleFactorTestValue(); | |
}); | |
addTearDown(tester.platformDispatcher.clearTextScaleFactorTestValue); |
deactivated: false, sourceUrl: '/foo/3', stillUrl: null), | ||
}; | ||
|
||
runSmokeTest([ |
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 five runSmokeTest
calls end up with colliding test names:
00:02 +105: ReactionChipsList smoke: no names / text / ltr / text scale: 1.0
00:02 +106: ReactionChipsList smoke: no names / text / ltr / text scale: 1.0
00:02 +107: ReactionChipsList smoke: no names / text / ltr / text scale: 1.0
00:02 +108: ReactionChipsList smoke: no names / text / ltr / text scale: 1.0
00:02 +109: ReactionChipsList smoke: no names / text / ltr / text scale: 1.0
Let's do something like:
runSmokeTest([ | |
runSmokeTest('unknown user', [ |
and then the names can be like "smoke: unknown user / no names / text / ltr / text scale: 1.0".
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 names will also be helpful for readers of the test source, to express the purpose of each test case.
final i1 = {'emoji_name': 'twocents', 'emoji_code': '181', 'reaction_type': 'realm_emoji'}; | ||
final i2 = {'emoji_name': 'twocents', 'emoji_code': '182', 'reaction_type': 'realm_emoji'}; | ||
|
||
// Base JSON for the one"Zulip extra emoji" reaction. Just missing user_id. |
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:
// Base JSON for the one"Zulip extra emoji" reaction. Just missing user_id. | |
// Base JSON for the one "Zulip extra emoji" reaction. Just missing user_id. |
// Base JSON for various image emoji reactions. Just missing user_id. | ||
final i1 = {'emoji_name': 'twocents', 'emoji_code': '181', 'reaction_type': 'realm_emoji'}; | ||
final i2 = {'emoji_name': 'twocents', 'emoji_code': '182', 'reaction_type': 'realm_emoji'}; | ||
|
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 category of "image emoji" includes both the reaction types zulip_extra_emoji
and realm_emoji
; this list is only the latter, with the former coming later. So e.g.:
// Base JSON for various image emoji reactions. Just missing user_id. | |
final i1 = {'emoji_name': 'twocents', 'emoji_code': '181', 'reaction_type': 'realm_emoji'}; | |
final i2 = {'emoji_name': 'twocents', 'emoji_code': '182', 'reaction_type': 'realm_emoji'}; | |
// Base JSON for various realm-emoji reactions. Just missing user_id. | |
final i1 = {'emoji_name': 'twocents', 'emoji_code': '181', 'reaction_type': 'realm_emoji'}; | |
final i2 = {'emoji_name': 'twocents', 'emoji_code': '182', 'reaction_type': 'realm_emoji'}; | |
final i1 = {'emoji_name': 'twocents', 'emoji_code': '181', 'reaction_type': 'realm_emoji'}; | ||
final i2 = {'emoji_name': 'twocents', 'emoji_code': '182', 'reaction_type': 'realm_emoji'}; |
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.
final i1 = {'emoji_name': 'twocents', 'emoji_code': '181', 'reaction_type': 'realm_emoji'}; | |
final i2 = {'emoji_name': 'twocents', 'emoji_code': '182', 'reaction_type': 'realm_emoji'}; | |
final i1 = {'emoji_name': 'twocents', 'emoji_code': '181', 'reaction_type': 'realm_emoji'}; | |
final i2 = {'emoji_name': 'threecents', 'emoji_code': '182', 'reaction_type': 'realm_emoji'}; |
At least I think this is what you meant — it's what matches realmEmoji
below.
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.
Yep! Thanks!
These calls only need to happen once, at the top of `main`: zulip#410 (comment)
a3d0070
to
b4b6648
Compare
Thanks! Revision pushed. |
And also support: - removing a reaction you've already made, and - joining in on existing reactions that other people have made. As is our habit with the message list, this aims to be faithful to the web app, as accessed today. That should be a good baseline to make mobile-specific adjustments from. (In particular I think we may want larger touch targets.) Unlike the web app, we use a font instead of a sprite sheet to render Unicode emoji. This means that we, unlike web, have to account for text-layout algorithms, and things like font metrics. So if Unicode emoji appear noticeably differently from web, that probably has something to do with it. Fixes: zulip#121 Fixes-partly: zulip#125
These calls only need to happen once, at the top of `main`: zulip#410 (comment)
This teardown is already added in setupToMessageActionSheet, which is called near the top of every test.
Thanks! LGTM; merging. |
b4b6648
to
8f43bc6
Compare
Great! Thanks for all your reviews and help with this. |
We should also use this font for Unicode emojis elsewhere, such as message content, users' names, and so on. But the proper layout of these chips is especially sensitive to how these emojis get rendered, and apparently the system emoji font can vary quite a bit on Android (same link as removed in the TODO): zulip#410 (comment) So we'd like to converge on one font here (at least for Android) as soon as possible.
We should also use this font for Unicode emojis elsewhere, such as message content, users' names, and so on. But the proper layout of these chips is especially sensitive to how these emojis get rendered, and apparently the system emoji font can vary quite a bit on Android (same link as removed in the TODO): zulip#410 (comment) So we'd like to converge on one font here (at least for Android) as soon as possible.
We should also use this font for Unicode emojis elsewhere, such as message content, users' names, and so on. But the proper layout of these chips is especially sensitive to how these emojis get rendered, and apparently the system emoji font can vary quite a bit on Android (same link as removed in the TODO): zulip#410 (comment) So we'd like to converge on one font here (at least for Android) as soon as possible.
Fixes #121.
Fixes #125.