Skip to content

Commit 3069f62

Browse files
content: Parse emojiUnicode in UnicodeEmojiNode
1 parent 93a1701 commit 3069f62

File tree

3 files changed

+38
-17
lines changed

3 files changed

+38
-17
lines changed

lib/model/content.dart

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -438,22 +438,24 @@ abstract class EmojiNode extends InlineContentNode {
438438
}
439439

440440
class UnicodeEmojiNode extends EmojiNode {
441-
const UnicodeEmojiNode({super.debugHtmlNode, required this.text});
441+
const UnicodeEmojiNode({super.debugHtmlNode, required this.emojiName, required this.emojiUnicode});
442442

443-
final String text;
443+
final String emojiName;
444+
final String? emojiUnicode;
444445

445446
@override
446447
bool operator ==(Object other) {
447-
return other is UnicodeEmojiNode && other.text == text;
448+
return other is UnicodeEmojiNode && other.emojiName == emojiName && other.emojiUnicode == emojiUnicode;
448449
}
449450

450451
@override
451-
int get hashCode => Object.hash('UnicodeEmojiNode', text);
452+
int get hashCode => Object.hash('UnicodeEmojiNode', emojiName, emojiUnicode);
452453

453454
@override
454455
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
455456
super.debugFillProperties(properties);
456-
properties.add(StringProperty('text', text));
457+
properties.add(StringProperty('emojiName', emojiName));
458+
properties.add(StringProperty('emojiUnicode', emojiUnicode));
457459
}
458460
}
459461

@@ -568,7 +570,8 @@ class _ZulipContentParser {
568570
&& classes.length == 2
569571
&& classes.contains('emoji')
570572
&& classes.every(_emojiClassRegexp.hasMatch)) {
571-
return UnicodeEmojiNode(text: element.text, debugHtmlNode: debugHtmlNode);
573+
final emojiUnicode = tryParseEmojiCodeToUnicode(classes.elementAt(1).replaceFirst('emoji-', ''));
574+
return UnicodeEmojiNode(emojiName: element.text, emojiUnicode: emojiUnicode, debugHtmlNode: debugHtmlNode);
572575
}
573576

574577
if (localName == 'img'
@@ -627,6 +630,25 @@ class _ZulipContentParser {
627630
return ListNode(listStyle!, items, debugHtmlNode: debugHtmlNode);
628631
}
629632

633+
// Ported from https://github.com/zulip/zulip-mobile/tree/main/src/emoji/data.js
634+
//
635+
// Which was in turn ported from https://github.com/zulip/zulip/blob/main/zerver/models.py
636+
// and that describes the encoding as follows:
637+
//
638+
// > * For Unicode emoji, [emoji_code is] a dash-separated hex encoding of
639+
// > the sequence of Unicode codepoints that define this emoji in the
640+
// > Unicode specification. For examples, see "non_qualified" or
641+
// > "unified" in the following data, with "non_qualified" taking
642+
// > precedence when both present:
643+
// > https://raw.githubusercontent.com/iamcal/emoji-data/master/emoji_pretty.json
644+
String? tryParseEmojiCodeToUnicode(String code) {
645+
try {
646+
return String.fromCharCodes(code.split('-').map((hex) => int.parse(hex, radix: 16)));
647+
} catch (_) {
648+
return null;
649+
}
650+
}
651+
630652
BlockContentNode parseCodeBlock(dom.Element divElement) {
631653
assert(_debugParserContext == _ParserContext.block);
632654
final mainElement = () {

lib/widgets/content.dart

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -449,8 +449,10 @@ class _InlineContentBuilder {
449449
return WidgetSpan(alignment: PlaceholderAlignment.middle,
450450
child: UserMention(node: node));
451451
} else if (node is UnicodeEmojiNode) {
452-
return WidgetSpan(alignment: PlaceholderAlignment.middle,
453-
child: MessageUnicodeEmoji(node: node));
452+
return switch (node.emojiUnicode) {
453+
String unicode => TextSpan(text: unicode, recognizer: _recognizer),
454+
null => WidgetSpan(alignment: PlaceholderAlignment.middle, child: MessageUnicodeEmojiFallback(emojiName: node.emojiName)),
455+
};
454456
} else if (node is ImageEmojiNode) {
455457
return WidgetSpan(alignment: PlaceholderAlignment.middle,
456458
child: MessageImageEmoji(node: node));
@@ -609,20 +611,17 @@ class UserMention extends StatelessWidget {
609611
// borderRadius: BorderRadius.all(Radius.circular(3))));
610612
}
611613

612-
class MessageUnicodeEmoji extends StatelessWidget {
613-
const MessageUnicodeEmoji({super.key, required this.node});
614+
class MessageUnicodeEmojiFallback extends StatelessWidget {
615+
const MessageUnicodeEmojiFallback({super.key, required this.emojiName});
614616

615-
final UnicodeEmojiNode node;
617+
final String emojiName;
616618

617619
@override
618620
Widget build(BuildContext context) {
619-
// TODO(#58) get spritesheet and show actual emoji glyph
620-
final text = node.text;
621621
return Container(
622622
padding: const EdgeInsets.all(2),
623-
decoration: BoxDecoration(
624-
color: Colors.white, border: Border.all(color: Colors.purple)),
625-
child: Text(text));
623+
decoration: BoxDecoration(color: Colors.white, border: Border.all(color: Colors.purple)),
624+
child: Text(emojiName));
626625
}
627626
}
628627

test/model/content_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ void main() {
143143
testParseInline('parse Unicode emoji',
144144
// ":thumbs_up:"
145145
'<p><span aria-label="thumbs up" class="emoji emoji-1f44d" role="img" title="thumbs up">:thumbs_up:</span></p>',
146-
const UnicodeEmojiNode(text: ':thumbs_up:'));
146+
const UnicodeEmojiNode(emojiName: ':thumbs_up:', emojiUnicode: '\u{1f44d}'));
147147

148148
testParseInline('parse custom emoji',
149149
// ":flutter:"

0 commit comments

Comments
 (0)