Skip to content

Commit ac55b0e

Browse files
committed
content: Parse data-animated on image-preview HTML
1 parent 9316aac commit ac55b0e

File tree

2 files changed

+38
-10
lines changed

2 files changed

+38
-10
lines changed

lib/model/content.dart

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ class ImagePreviewNode extends BlockContentNode {
551551
/// authentication credentials to the request.
552552
final String srcUrl;
553553

554-
/// The thumbnail URL of the image.
554+
/// The thumbnail URL of the image and whether it has an animated version.
555555
///
556556
/// [ImageThumbnailLocator.urlPath] is a relative URL string.
557557
///
@@ -596,11 +596,13 @@ class ImagePreviewNode extends BlockContentNode {
596596
}
597597
}
598598

599-
/// Data to locate an image thumbnail.
599+
/// Data to locate an image thumbnail,
600+
/// and whether the image has an animated version.
600601
@immutable
601602
class ImageThumbnailLocator extends DiagnosticableTree {
602603
ImageThumbnailLocator({
603604
required this.urlPath,
605+
required this.animated,
604606
}) : assert(urlPath.startsWith(urlPathPrefix));
605607

606608
/// The relative URL string for the default format,
@@ -609,21 +611,27 @@ class ImageThumbnailLocator extends DiagnosticableTree {
609611
/// It may not work without adding authentication credentials to the request.
610612
final String urlPath;
611613

614+
final bool animated;
615+
612616
static const urlPathPrefix = '/user_uploads/thumbnail/';
613617

614618
@override
615619
bool operator ==(Object other) {
616620
if (other is! ImageThumbnailLocator) return false;
617-
return urlPath == other.urlPath;
621+
return urlPath == other.urlPath
622+
&& animated == other.animated;
618623
}
619624

620625
@override
621-
int get hashCode => Object.hash('ImageThumbnailLocator', urlPath);
626+
int get hashCode => Object.hash('ImageThumbnailLocator', urlPath, animated);
622627

623628
@override
624629
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
625630
super.debugFillProperties(properties);
626631
properties.add(StringProperty('urlPath', urlPath));
632+
properties.add(FlagProperty('animated', value: animated,
633+
ifTrue: 'animated',
634+
ifFalse: 'not animated'));
627635
}
628636
}
629637

@@ -1446,7 +1454,9 @@ class _ZulipContentParser {
14461454
// For why we recognize this as the thumbnail form, see discussion:
14471455
// https://chat.zulip.org/#narrow/channel/412-api-documentation/topic/documenting.20inline.20images/near/2279872
14481456
srcUrl = href;
1449-
thumbnail = ImageThumbnailLocator(urlPath: src);
1457+
thumbnail = ImageThumbnailLocator(
1458+
urlPath: src,
1459+
animated: imgElement.attributes['data-animated'] == 'true');
14501460
} else {
14511461
// Known cases this handles:
14521462
// - `src` starts with CAMO_URI, a server variable (e.g. on Zulip Cloud

test/model/content_test.dart

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -735,14 +735,31 @@ class ContentExample {
735735
'<img data-original-dimensions="6000x4000" src="/user_uploads/thumbnail/2/ce/nvoNL2LaZOciwGZ-FYagddtK/image.jpg/840x560.webp"></a></div>', [
736736
ImagePreviewNodeList([
737737
ImagePreviewNode(srcUrl: '/user_uploads/2/ce/nvoNL2LaZOciwGZ-FYagddtK/image.jpg',
738-
thumbnail: ImageThumbnailLocator(
738+
thumbnail: ImageThumbnailLocator(animated: false,
739739
urlPath: '/user_uploads/thumbnail/2/ce/nvoNL2LaZOciwGZ-FYagddtK/image.jpg/840x560.webp'),
740740
loading: false,
741741
originalWidth: 6000,
742742
originalHeight: 4000),
743743
]),
744744
]);
745745

746+
static final imagePreviewSingleAnimated = ContentExample(
747+
'single image preview, with animated version',
748+
// https://chat.zulip.org/#narrow/channel/7-test-here/topic/Thumbnails/near/2298790
749+
"[2c8d985d.gif](/user_uploads/2/9f/tZ9c5ZmsI_cSDZ6ZdJmW8pt4/2c8d985d.gif)",
750+
'<div class="message_inline_image">'
751+
'<a href="/user_uploads/2/9f/tZ9c5ZmsI_cSDZ6ZdJmW8pt4/2c8d985d.gif" title="2c8d985d.gif">'
752+
'<img data-animated="true" data-original-content-type="image/gif" data-original-dimensions="64x64" src="/user_uploads/thumbnail/2/9f/tZ9c5ZmsI_cSDZ6ZdJmW8pt4/2c8d985d.gif/840x560-anim.webp"></a></div>', [
753+
ImagePreviewNodeList([
754+
ImagePreviewNode(srcUrl: '/user_uploads/2/9f/tZ9c5ZmsI_cSDZ6ZdJmW8pt4/2c8d985d.gif',
755+
thumbnail: ImageThumbnailLocator(animated: true,
756+
urlPath: '/user_uploads/thumbnail/2/9f/tZ9c5ZmsI_cSDZ6ZdJmW8pt4/2c8d985d.gif/840x560-anim.webp'),
757+
loading: false,
758+
originalWidth: 64,
759+
originalHeight: 64),
760+
]),
761+
]);
762+
746763
static final imagePreviewSingleNoDimensions = ContentExample(
747764
'single image preview no dimensions',
748765
// https://chat.zulip.org/#narrow/stream/7-test-here/topic/Thumbnails/near/1893590
@@ -752,7 +769,7 @@ class ContentExample {
752769
'<img src="/user_uploads/thumbnail/2/c3/wb9FXk8Ej6qIc28aWKcqUogD/image.jpg/840x560.webp"/></a></div>', [
753770
ImagePreviewNodeList([
754771
ImagePreviewNode(srcUrl: '/user_uploads/2/c3/wb9FXk8Ej6qIc28aWKcqUogD/image.jpg',
755-
thumbnail: ImageThumbnailLocator(
772+
thumbnail: ImageThumbnailLocator(animated: false,
756773
urlPath: '/user_uploads/thumbnail/2/c3/wb9FXk8Ej6qIc28aWKcqUogD/image.jpg/840x560.webp'),
757774
loading: false,
758775
originalWidth: null,
@@ -865,13 +882,13 @@ class ContentExample {
865882
]),
866883
ImagePreviewNodeList([
867884
ImagePreviewNode(srcUrl: '/user_uploads/2/9b/WkDt2Qsy79iwf3sM9EMp9fYL/image.jpg',
868-
thumbnail: ImageThumbnailLocator(
885+
thumbnail: ImageThumbnailLocator(animated: false,
869886
urlPath: '/user_uploads/thumbnail/2/9b/WkDt2Qsy79iwf3sM9EMp9fYL/image.jpg/840x560.webp'),
870887
loading: false,
871888
originalWidth: null,
872889
originalHeight: null),
873890
ImagePreviewNode(srcUrl: '/user_uploads/2/70/pVeI52TwFUEoFE2qT_u9AMCO/image2.jpg',
874-
thumbnail: ImageThumbnailLocator(
891+
thumbnail: ImageThumbnailLocator(animated: false,
875892
urlPath: '/user_uploads/thumbnail/2/70/pVeI52TwFUEoFE2qT_u9AMCO/image2.jpg/840x560.webp'),
876893
loading: false,
877894
originalWidth: null,
@@ -1425,7 +1442,7 @@ class ContentExample {
14251442
]),
14261443
ImagePreviewNodeList([
14271444
ImagePreviewNode(srcUrl: '/user_uploads/2/6f/KS3vNT9c2tbMfMBkSbQF_Jlj/image2.jpg',
1428-
thumbnail: ImageThumbnailLocator(
1445+
thumbnail: ImageThumbnailLocator(animated: false,
14291446
urlPath: '/user_uploads/thumbnail/2/6f/KS3vNT9c2tbMfMBkSbQF_Jlj/image2.jpg/840x560.webp'),
14301447
loading: false,
14311448
originalWidth: 2760,
@@ -1848,6 +1865,7 @@ void main() async {
18481865
testParseExample(ContentExample.mathBlockBetweenImagePreviews);
18491866

18501867
testParseExample(ContentExample.imagePreviewSingle);
1868+
testParseExample(ContentExample.imagePreviewSingleAnimated);
18511869
testParseExample(ContentExample.imagePreviewSingleNoDimensions);
18521870
testParseExample(ContentExample.imagePreviewSingleNoThumbnail);
18531871
testParseExample(ContentExample.imagePreviewSingleLoadingPlaceholder);

0 commit comments

Comments
 (0)