diff --git a/fluxer_app/src/features/channel/components/MessageReactions.tsx b/fluxer_app/src/features/channel/components/MessageReactions.tsx index a462b1ae6..76591142d 100644 --- a/fluxer_app/src/features/channel/components/MessageReactions.tsx +++ b/fluxer_app/src/features/channel/components/MessageReactions.tsx @@ -78,14 +78,10 @@ const MessageReactionItem = observer( const {i18n} = useLingui(); const [hoverRef, isHovering] = useHover(); const [prevCount, setPrevCount] = useState(reaction.count); - const [animationSyncKey, setAnimationSyncKey] = useState(0); const [emojiInfoOpen, setEmojiInfoOpen] = useState(false); const [selectedEmoji, setSelectedEmoji] = useState(null); const [tooltipHovering, setTooltipHovering] = useState(false); const isMobile = MobileLayout.isMobileLayout(); - const handleTooltipAnimationSync = useCallback(() => { - setAnimationSyncKey((prev) => prev + 1); - }, []); useEffect(() => { if (prevCount !== reaction.count) { setPrevCount(reaction.count); @@ -186,6 +182,7 @@ const MessageReactionItem = observer( diff --git a/fluxer_app/src/features/messaging/components/ReactionImage.tsx b/fluxer_app/src/features/messaging/components/ReactionImage.tsx index b2f79079e..6b592d2e1 100644 --- a/fluxer_app/src/features/messaging/components/ReactionImage.tsx +++ b/fluxer_app/src/features/messaging/components/ReactionImage.tsx @@ -1,6 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -import {useExpressionImagePreload} from '@app/features/expressions/utils/ExpressionImageCache'; import type React from 'react'; type ReactionImageProps = Omit, 'alt' | 'src'> & { @@ -8,15 +7,6 @@ type ReactionImageProps = Omit, 'alt' alt: string; }; -export const ReactionImage: React.FC = ({ - src, - alt, - decoding = 'async', - loading = 'eager', - ...props -}) => { - useExpressionImagePreload(src); - return ( - {alt} - ); +export const ReactionImage: React.FC = ({src, alt, loading = 'eager', ...props}) => { + return {alt}; }; diff --git a/fluxer_app/src/features/messaging/components/popouts/ReactionTooltip.tsx b/fluxer_app/src/features/messaging/components/popouts/ReactionTooltip.tsx index f28902ff9..ece4f1457 100644 --- a/fluxer_app/src/features/messaging/components/popouts/ReactionTooltip.tsx +++ b/fluxer_app/src/features/messaging/components/popouts/ReactionTooltip.tsx @@ -28,40 +28,24 @@ export const ReactionTooltip = observer( reaction, children, hoveredEmojiUrl, - animationSyncKey, - onRequestAnimationSync, onTooltipHoverChange, }: { message: Message; reaction: MessageReaction; children: React.ReactElement & {ref?: React.Ref}>; hoveredEmojiUrl?: string | null; - animationSyncKey?: number; - onRequestAnimationSync?: () => void; onTooltipHoverChange?: (hovering: boolean) => void; }) => { const {i18n} = useLingui(); const tooltip = useHoverFloatingTooltip(500); - const prevIsOpenRef = useRef(false); - useEffect(() => { - if (tooltip.state.isOpen && !prevIsOpenRef.current) { - onRequestAnimationSync?.(); - } - prevIsOpenRef.current = tooltip.state.isOpen; - }, [tooltip.state.isOpen, onRequestAnimationSync]); useEffect(() => { onTooltipHoverChange?.(tooltip.state.isOpen); }, [tooltip.state.isOpen, onTooltipHoverChange]); const {fetchStatus} = useReactionUsers(message.id, reaction.emoji); const isLoading = fetchStatus === 'pending'; const tooltipText = getReactionTooltip(message, reaction.emoji); - const emojiIdentifier = reaction.emoji.id ?? reaction.emoji.name; - const tooltipEmojiKey = `${emojiIdentifier}-${animationSyncKey ?? 0}`; - const fallbackEmojiUrl = useEmojiURL({ - emoji: reaction.emoji, - isHovering: tooltip.state.isOpen, - forceAnimate: tooltip.state.isOpen, - }); + const tooltipEmojiKey = reaction.emoji.id ?? reaction.emoji.name; + const fallbackEmojiUrl = useEmojiURL({emoji: reaction.emoji}); const emojiUrl = hoveredEmojiUrl ?? fallbackEmojiUrl; const errorRetryRef = useRef(false); useEffect(() => { diff --git a/fluxer_app/src/features/messaging/utils/MessageReactionUtils.ts b/fluxer_app/src/features/messaging/utils/MessageReactionUtils.ts index 130c8cc72..eb61e2040 100644 --- a/fluxer_app/src/features/messaging/utils/MessageReactionUtils.ts +++ b/fluxer_app/src/features/messaging/utils/MessageReactionUtils.ts @@ -1,22 +1,17 @@ // SPDX-License-Identifier: AGPL-3.0-or-later import i18n from '@app/app/I18n'; -import {useShouldAnimate} from '@app/features/app/hooks/useShouldAnimate'; import Channels from '@app/features/channel/state/Channels'; import type {UnicodeEmoji} from '@app/features/emoji/types/EmojiTypes'; import EmojiCatalog from '@app/features/expressions/utils/EmojiCatalog'; -import * as EmojiImageUtils from '@app/features/expressions/utils/EmojiImageUtils'; import {getSkinTonedSurrogate} from '@app/features/expressions/utils/SkinToneUtils'; import type {Message} from '@app/features/messaging/models/MessagingMessage'; import MessageReactions from '@app/features/messaging/state/MessageReactions'; -import * as ImageCacheUtils from '@app/features/messaging/utils/ImageCacheUtils'; -import {setUrlQueryParams} from '@app/features/messaging/utils/MessagingUrlUtils'; import {getReactionKey, type ReactionEmoji} from '@app/features/messaging/utils/ReactionEmoji'; -import * as AvatarSourceUtils from '@app/features/user/utils/AvatarSourceUtils'; +import * as ReactionUtils from '@app/features/messaging/utils/ReactionUtils'; import * as DisplayNameUtils from '@app/features/user/utils/DisplayNameUtils'; import {getCurrentLocale} from '@app/features/user/utils/LocaleUtils'; import {msg, plural} from '@lingui/core/macro'; -import {useEffect, useState} from 'react'; const REACTED_BY_DESCRIPTOR = msg({ message: '{emojiName} reacted by {reactors}', @@ -97,10 +92,6 @@ export function getEmojiNameWithColons(emoji: ReactionEmoji): string { return name ? `:${name}:` : surrogate; } -function getCustomEmojiURL(id: string, animated: boolean, size: number): string { - return setUrlQueryParams(AvatarSourceUtils.getEmojiURL({id, animated}), {size, quality: 'lossless'}); -} - export interface EmojiURLParams { readonly emoji: ReactionEmoji; readonly isHovering?: boolean; @@ -116,26 +107,6 @@ export function useEmojiURL({ forceAnimate = false, enabled = true, }: EmojiURLParams): string | null { - const shouldAnimate = useShouldAnimate({ - kind: 'emoji', - isHovering: isHovering || forceAnimate, - }); - const staticUrl = - emoji.id == null - ? EmojiImageUtils.getEmojiURL(EmojiCatalog.normalizeShortcodeToSurrogate(emoji.name)) - : getCustomEmojiURL(emoji.id, false, size); - const animatedUrl = emoji.id != null && emoji.animated ? getCustomEmojiURL(emoji.id, true, size) : null; - const [loadedAnimatedUrl, setLoadedAnimatedUrl] = useState(() => - ImageCacheUtils.hasImage(animatedUrl) ? animatedUrl : null, - ); - useEffect(() => { - if (!enabled) return; - ImageCacheUtils.pinImage(staticUrl); - }, [enabled, staticUrl]); - useEffect(() => { - if (!enabled || !shouldAnimate || !animatedUrl) return; - return ImageCacheUtils.loadImage(animatedUrl, () => setLoadedAnimatedUrl(animatedUrl)); - }, [animatedUrl, enabled, shouldAnimate]); - if (!enabled) return null; - return shouldAnimate && animatedUrl === loadedAnimatedUrl ? animatedUrl : staticUrl; + const url = ReactionUtils.useEmojiURL({emoji, isHovering, size, forceAnimate}); + return enabled ? url : null; } diff --git a/fluxer_app/src/features/messaging/utils/ReactionUtils.ts b/fluxer_app/src/features/messaging/utils/ReactionUtils.ts index 2b7a94c6d..28dad39bb 100644 --- a/fluxer_app/src/features/messaging/utils/ReactionUtils.ts +++ b/fluxer_app/src/features/messaging/utils/ReactionUtils.ts @@ -4,13 +4,12 @@ import i18n from '@app/app/I18n'; import {useShouldAnimate} from '@app/features/app/hooks/useShouldAnimate'; import Channels from '@app/features/channel/state/Channels'; import type {UnicodeEmoji} from '@app/features/emoji/types/EmojiTypes'; +import {buildCustomEmojiURL} from '@app/features/expressions/utils/CustomEmojiImageUrl'; import * as EmojiUtils from '@app/features/expressions/utils/EmojiUtils'; import {getSkinTonedSurrogate} from '@app/features/expressions/utils/SkinToneUtils'; import UnicodeEmojis from '@app/features/expressions/utils/UnicodeEmojis'; import type {Message} from '@app/features/messaging/models/MessagingMessage'; import MessageReactions from '@app/features/messaging/state/MessageReactions'; -import {setUrlQueryParams} from '@app/features/messaging/utils/MessagingUrlUtils'; -import * as AvatarUtils from '@app/features/user/utils/AvatarUtils'; import {getCurrentLocale} from '@app/features/user/utils/LocaleUtils'; import * as NicknameUtils from '@app/features/user/utils/NicknameUtils'; import {msg, plural} from '@lingui/core/macro'; @@ -101,7 +100,7 @@ export function getEmojiNameWithColons(emoji: ReactionEmoji): string { export function useEmojiURL({ emoji, isHovering = false, - size = 128, + size, forceAnimate = false, }: { emoji: ReactionEmoji; @@ -111,11 +110,11 @@ export function useEmojiURL({ }): string | null { const shouldAnimate = useShouldAnimate({ kind: 'emoji', + isAnimated: emoji.animated === true, isHovering: isHovering || forceAnimate, }); if (emoji.id == null) { return EmojiUtils.getEmojiURL(UnicodeEmojis.normalizeEmojiNameToSurrogate(emoji.name)); } - const url = AvatarUtils.getEmojiURL({id: emoji.id, animated: shouldAnimate}); - return setUrlQueryParams(url, {size, quality: 'lossless'}); + return buildCustomEmojiURL({id: emoji.id, animated: emoji.animated === true && shouldAnimate, size}); }