mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-07 19:22:14 +09:00
fix(app): retry emoji picker images that fail to load (#3151)
This commit is contained in:
@@ -11,6 +11,7 @@ import type {FlatEmoji} from '@app/features/emoji/types/EmojiTypes';
|
|||||||
import {checkEmojiAvailability} from '@app/features/expressions/utils/ExpressionPermissionUtils';
|
import {checkEmojiAvailability} from '@app/features/expressions/utils/ExpressionPermissionUtils';
|
||||||
import {getEmojiDisplayDataWithSkinTone} from '@app/features/expressions/utils/SkinToneUtils';
|
import {getEmojiDisplayDataWithSkinTone} from '@app/features/expressions/utils/SkinToneUtils';
|
||||||
import UnicodeEmojis, {EMOJI_SPRITES} from '@app/features/expressions/utils/UnicodeEmojis';
|
import UnicodeEmojis, {EMOJI_SPRITES} from '@app/features/expressions/utils/UnicodeEmojis';
|
||||||
|
import {loadImage} from '@app/features/messaging/utils/ImageCacheUtils';
|
||||||
import {getEmojiRenderUrl} from '@app/features/messaging/utils/markdown/EmojiDetector';
|
import {getEmojiRenderUrl} from '@app/features/messaging/utils/markdown/EmojiDetector';
|
||||||
import {EmojiContextMenuItems} from '@app/features/ui/action_menu/items/EmojiContextMenuItems';
|
import {EmojiContextMenuItems} from '@app/features/ui/action_menu/items/EmojiContextMenuItems';
|
||||||
import * as ContextMenuCommands from '@app/features/ui/commands/ContextMenuCommands';
|
import * as ContextMenuCommands from '@app/features/ui/commands/ContextMenuCommands';
|
||||||
@@ -25,9 +26,34 @@ type PickerEmojiImageProps = React.ImgHTMLAttributes<HTMLImageElement> & {
|
|||||||
alt: string;
|
alt: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PICKER_IMAGE_RETRY_LIMIT = 3;
|
||||||
|
|
||||||
const PickerEmojiImage = ({src, alt, ...props}: PickerEmojiImageProps) => {
|
const PickerEmojiImage = ({src, alt, ...props}: PickerEmojiImageProps) => {
|
||||||
const imageRef = useRef<HTMLImageElement | null>(null);
|
const imageRef = useRef<HTMLImageElement | null>(null);
|
||||||
const hasLoadedRef = useRef(false);
|
const hasLoadedRef = useRef(false);
|
||||||
|
const retriesRef = useRef(0);
|
||||||
|
const cancelRetryRef = useRef<(() => void) | null>(null);
|
||||||
|
useEffect(() => {
|
||||||
|
retriesRef.current = 0;
|
||||||
|
return () => {
|
||||||
|
cancelRetryRef.current?.();
|
||||||
|
cancelRetryRef.current = null;
|
||||||
|
};
|
||||||
|
}, [src]);
|
||||||
|
const handleError = () => {
|
||||||
|
if (retriesRef.current >= PICKER_IMAGE_RETRY_LIMIT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
retriesRef.current += 1;
|
||||||
|
cancelRetryRef.current?.();
|
||||||
|
cancelRetryRef.current = loadImage(src, () => {
|
||||||
|
cancelRetryRef.current = null;
|
||||||
|
const image = imageRef.current;
|
||||||
|
if (image != null && image.getAttribute('src') === src) {
|
||||||
|
image.src = src;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
const handleLoad = (event: React.SyntheticEvent<HTMLImageElement>) => {
|
const handleLoad = (event: React.SyntheticEvent<HTMLImageElement>) => {
|
||||||
const view = event.currentTarget?.ownerDocument?.defaultView ?? window;
|
const view = event.currentTarget?.ownerDocument?.defaultView ?? window;
|
||||||
view.requestAnimationFrame(() => {
|
view.requestAnimationFrame(() => {
|
||||||
@@ -47,6 +73,7 @@ const PickerEmojiImage = ({src, alt, ...props}: PickerEmojiImageProps) => {
|
|||||||
alt={alt}
|
alt={alt}
|
||||||
className={hasLoadedRef.current ? styles.emojiImage : clsx(styles.emojiImage, styles.emojiImageLoading)}
|
className={hasLoadedRef.current ? styles.emojiImage : clsx(styles.emojiImage, styles.emojiImageLoading)}
|
||||||
onLoad={hasLoadedRef.current ? undefined : handleLoad}
|
onLoad={hasLoadedRef.current ? undefined : handleLoad}
|
||||||
|
onError={hasLoadedRef.current ? undefined : handleError}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user