mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 13:05:32 +09:00
fix(app): keep animated embed images animated (#1892)
This commit is contained in:
1 parent
50a947a722
commit
3fe6217809
2 files changed
+47
-24
No files matched your search
+36
-5
@@ -2,7 +2,13 @@
|
||||
|
||||
import type {Message} from '@app/features/messaging/models/MessagingMessage';
|
||||
import {getEmbedMediaDimensions} from '@app/features/messaging/utils/MediaDimensionConfig';
|
||||
import {buildMediaProxyURL, resolvePreferredImageFormat} from '@app/features/messaging/utils/MediaProxyUtils';
|
||||
import {
|
||||
buildAnimatedImageProxyURL,
|
||||
buildMediaProxyURL,
|
||||
mediaDevicePixelRatio,
|
||||
resolvePreferredImageFormat,
|
||||
stripMediaProxyParams,
|
||||
} from '@app/features/messaging/utils/MediaProxyUtils';
|
||||
import {Logger} from '@app/features/platform/utils/AppLogger';
|
||||
import * as ColorUtils from '@app/features/theme/utils/ColorUtils';
|
||||
import {createCalculator, type MediaDimensionCalculator} from '@app/features/ui/utils/DimensionUtils';
|
||||
@@ -128,15 +134,40 @@ export const calculateMediaDimensions = (media: Required<EmbedMedia>): MediaDime
|
||||
const {dimensions} = mediaCalculator.calculate({width: media.width, height: media.height});
|
||||
return dimensions;
|
||||
};
|
||||
const toEmbedMediaPixels = (layoutWidth: number, layoutHeight: number): MediaDimensions => {
|
||||
const ratio = mediaDevicePixelRatio();
|
||||
return {width: Math.round(layoutWidth * ratio), height: Math.round(layoutHeight * ratio)};
|
||||
};
|
||||
export const getOptimizedMediaURL = (proxyURL: string, width: number, height: number, contentType?: string): string => {
|
||||
const targetWidth = Math.round(width * 2);
|
||||
const targetHeight = Math.round(height * 2);
|
||||
const target = toEmbedMediaPixels(width, height);
|
||||
return buildMediaProxyURL(proxyURL, {
|
||||
format: resolvePreferredImageFormat(contentType),
|
||||
width: targetWidth,
|
||||
height: targetHeight,
|
||||
width: target.width,
|
||||
height: target.height,
|
||||
});
|
||||
};
|
||||
export const getOptimizedAnimatedMediaURL = (proxyURL: string, width: number, height: number): string => {
|
||||
if (!proxyURL) return proxyURL;
|
||||
const target = toEmbedMediaPixels(width, height);
|
||||
return buildAnimatedImageProxyURL(stripMediaProxyParams(proxyURL), target.width, target.height);
|
||||
};
|
||||
export const isAnimatedEmbedMedia = (media: Pick<EmbedMedia, 'content_type' | 'flags'>): boolean => {
|
||||
if (media.content_type === 'image/gif') return true;
|
||||
return ((media.flags ?? 0) & MessageAttachmentFlags.IS_ANIMATED) === MessageAttachmentFlags.IS_ANIMATED;
|
||||
};
|
||||
export const resolveEmbedImageSource = (
|
||||
media: Pick<EmbedMedia, 'content_type' | 'flags'> & {proxy_url: string},
|
||||
width: number,
|
||||
height: number,
|
||||
): {src: string; animated: boolean} => {
|
||||
const animated = isAnimatedEmbedMedia(media);
|
||||
return {
|
||||
src: animated
|
||||
? getOptimizedAnimatedMediaURL(media.proxy_url, width, height)
|
||||
: getOptimizedMediaURL(media.proxy_url, width, height, media.content_type),
|
||||
animated,
|
||||
};
|
||||
};
|
||||
export const mediaIdentityKey = (media?: EmbedMedia): string => {
|
||||
if (!media) return '';
|
||||
return [
|
||||
|
||||
+11
-19
@@ -3,11 +3,11 @@
|
||||
import {
|
||||
calculateMediaDimensions,
|
||||
type EmbedMediaRendererProps,
|
||||
getOptimizedMediaURL,
|
||||
getUrlHostname,
|
||||
isMediaMatureContent,
|
||||
isValidMedia,
|
||||
mediaPropsEqual,
|
||||
resolveEmbedImageSource,
|
||||
THUMBNAIL_SIZE,
|
||||
} from '@app/features/channel/components/embeds/channel_embed/ChannelEmbedShared';
|
||||
import {EmbedGif} from '@app/features/channel/components/embeds/media/EmbedGifv';
|
||||
@@ -16,10 +16,9 @@ import EmbedVideo from '@app/features/channel/components/embeds/media/EmbedVideo
|
||||
import {EmbedYouTube} from '@app/features/channel/components/embeds/media/EmbedYouTube';
|
||||
import {getInlineVideoLayoutConstraints} from '@app/features/channel/components/embeds/media/VideoDimensionUtils';
|
||||
import {getEmbedMediaDimensions} from '@app/features/messaging/utils/MediaDimensionConfig';
|
||||
import {buildAnimatedImageProxyURL, buildMediaProxyURL} from '@app/features/messaging/utils/MediaProxyUtils';
|
||||
import {buildMediaProxyURL} from '@app/features/messaging/utils/MediaProxyUtils';
|
||||
import messageStyles from '@app/features/theme/styles/Message.module.css';
|
||||
import FocusRing from '@app/features/ui/focus_ring/FocusRing';
|
||||
import {MessageAttachmentFlags} from '@fluxer/constants/src/ChannelConstants';
|
||||
import {observer} from 'mobx-react-lite';
|
||||
import {type FC, memo} from 'react';
|
||||
|
||||
@@ -76,7 +75,6 @@ const EmbedMediaRendererInner: FC<EmbedMediaRendererProps> = observer(
|
||||
if (isValidMedia(image)) {
|
||||
const {width, height} = calculateMediaDimensions(image);
|
||||
const isGif = image.content_type === 'image/gif' || image.url.toLowerCase().endsWith('.gif');
|
||||
const imageIsAnimated = (image.flags & MessageAttachmentFlags.IS_ANIMATED) === MessageAttachmentFlags.IS_ANIMATED;
|
||||
if (isGif) {
|
||||
return (
|
||||
<FocusRing
|
||||
@@ -105,6 +103,7 @@ const EmbedMediaRendererInner: FC<EmbedMediaRendererProps> = observer(
|
||||
</FocusRing>
|
||||
);
|
||||
}
|
||||
const resolvedImageSource = resolveEmbedImageSource(image, width, height);
|
||||
return (
|
||||
<FocusRing
|
||||
within
|
||||
@@ -112,7 +111,7 @@ const EmbedMediaRendererInner: FC<EmbedMediaRendererProps> = observer(
|
||||
data-flx="channel.embeds.embed.embed-media-renderer-inner.focus-ring--4"
|
||||
>
|
||||
<EmbedImage
|
||||
src={getOptimizedMediaURL(image.proxy_url, width, height, image.content_type)}
|
||||
src={resolvedImageSource.src}
|
||||
originalSrc={image.url}
|
||||
naturalWidth={image.width}
|
||||
naturalHeight={image.height}
|
||||
@@ -128,7 +127,7 @@ const EmbedMediaRendererInner: FC<EmbedMediaRendererProps> = observer(
|
||||
embedIndex={embedIndex}
|
||||
onDelete={onDelete}
|
||||
isPreview={isPreview}
|
||||
animated={imageIsAnimated}
|
||||
animated={resolvedImageSource.animated}
|
||||
alt={image.description ?? undefined}
|
||||
data-flx="channel.embeds.embed.embed-media-renderer-inner.embed-image"
|
||||
/>
|
||||
@@ -138,8 +137,6 @@ const EmbedMediaRendererInner: FC<EmbedMediaRendererProps> = observer(
|
||||
if (isValidMedia(thumbnail)) {
|
||||
const {width, height} = calculateMediaDimensions(thumbnail);
|
||||
const isGif = thumbnail.content_type === 'image/gif' || thumbnail.url.toLowerCase().endsWith('.gif');
|
||||
const thumbnailIsAnimated =
|
||||
(thumbnail.flags & MessageAttachmentFlags.IS_ANIMATED) === MessageAttachmentFlags.IS_ANIMATED;
|
||||
if (isGif) {
|
||||
return (
|
||||
<FocusRing
|
||||
@@ -167,6 +164,7 @@ const EmbedMediaRendererInner: FC<EmbedMediaRendererProps> = observer(
|
||||
</FocusRing>
|
||||
);
|
||||
}
|
||||
const thumbnailSource = resolveEmbedImageSource(thumbnail, width, height);
|
||||
return (
|
||||
<FocusRing
|
||||
within
|
||||
@@ -174,7 +172,7 @@ const EmbedMediaRendererInner: FC<EmbedMediaRendererProps> = observer(
|
||||
data-flx="channel.embeds.embed.embed-media-renderer-inner.focus-ring--6"
|
||||
>
|
||||
<EmbedImage
|
||||
src={getOptimizedMediaURL(thumbnail.proxy_url, width, height, thumbnail.content_type)}
|
||||
src={thumbnailSource.src}
|
||||
originalSrc={thumbnail.url}
|
||||
naturalWidth={thumbnail.width}
|
||||
naturalHeight={thumbnail.height}
|
||||
@@ -189,7 +187,7 @@ const EmbedMediaRendererInner: FC<EmbedMediaRendererProps> = observer(
|
||||
contentHash={thumbnail.content_hash}
|
||||
embedIndex={embedIndex}
|
||||
onDelete={onDelete}
|
||||
animated={thumbnailIsAnimated}
|
||||
animated={thumbnailSource.animated}
|
||||
alt={thumbnail.description ?? undefined}
|
||||
data-flx="channel.embeds.embed.embed-media-renderer-inner.embed-image--2"
|
||||
/>
|
||||
@@ -205,9 +203,7 @@ const InlineThumbnailRendererInner: FC<EmbedMediaRendererProps> = observer(
|
||||
if (!embed.thumbnail || !isValidMedia(embed.thumbnail)) return null;
|
||||
const thumbnail = embed.thumbnail;
|
||||
const width = Math.min(THUMBNAIL_SIZE, Math.round((THUMBNAIL_SIZE * thumbnail.width) / thumbnail.height));
|
||||
const thumbnailIsAnimated =
|
||||
thumbnail.content_type === 'image/gif' ||
|
||||
(thumbnail.flags & MessageAttachmentFlags.IS_ANIMATED) === MessageAttachmentFlags.IS_ANIMATED;
|
||||
const thumbnailSource = resolveEmbedImageSource(thumbnail, width, THUMBNAIL_SIZE);
|
||||
return (
|
||||
<FocusRing
|
||||
within
|
||||
@@ -215,11 +211,7 @@ const InlineThumbnailRendererInner: FC<EmbedMediaRendererProps> = observer(
|
||||
data-flx="channel.embeds.embed.inline-thumbnail-renderer-inner.focus-ring"
|
||||
>
|
||||
<EmbedImage
|
||||
src={
|
||||
thumbnail.content_type === 'image/gif'
|
||||
? buildAnimatedImageProxyURL(thumbnail.proxy_url, width * 2, THUMBNAIL_SIZE * 2)
|
||||
: getOptimizedMediaURL(thumbnail.proxy_url, width, THUMBNAIL_SIZE, thumbnail.content_type)
|
||||
}
|
||||
src={thumbnailSource.src}
|
||||
originalSrc={thumbnail.url}
|
||||
naturalWidth={thumbnail.width}
|
||||
naturalHeight={thumbnail.height}
|
||||
@@ -236,7 +228,7 @@ const InlineThumbnailRendererInner: FC<EmbedMediaRendererProps> = observer(
|
||||
embedIndex={embedIndex}
|
||||
onDelete={onDelete}
|
||||
isPreview={isPreview}
|
||||
animated={thumbnailIsAnimated}
|
||||
animated={thumbnailSource.animated}
|
||||
alt={thumbnail.description ?? undefined}
|
||||
data-flx="channel.embeds.embed.inline-thumbnail-renderer-inner.embed-image"
|
||||
/>
|
||||
|
||||
Reference in new issue
Block a user