From 03d145e467e1d54af40a32ed922abe06b2d04af0 Mon Sep 17 00:00:00 2001 From: Hailey Date: Wed, 27 Dec 2023 20:00:59 -0800 Subject: [PATCH] add gif embed player --- src/lib/strings/embed-player.ts | 27 ++-- .../com/util/post-embeds/ExternalGifEmbed.tsx | 124 ++++++++++++++++++ .../util/post-embeds/ExternalLinkEmbed.tsx | 8 +- .../util/post-embeds/ExternalPlayerEmbed.tsx | 7 +- 4 files changed, 152 insertions(+), 14 deletions(-) create mode 100644 src/view/com/util/post-embeds/ExternalGifEmbed.tsx diff --git a/src/lib/strings/embed-player.ts b/src/lib/strings/embed-player.ts index d848dd0ebd..d624c75ede 100644 --- a/src/lib/strings/embed-player.ts +++ b/src/lib/strings/embed-player.ts @@ -16,8 +16,7 @@ export type EmbedPlayerParams = | {type: 'apple_music_album'; albumId: string; playerUri: string} | {type: 'apple_music_song'; songId: string; playerUri: string} | {type: 'vimeo_video'; videoId: string; playerUri: string} - | {type: 'giphy_gif'; playerUri: string} - | {type: 'tenor_gif'; playerUri: string} + | {type: 'gif'; playerUri: string} export function parseEmbedPlayerFromUrl( url: string, @@ -187,7 +186,7 @@ export function parseEmbedPlayerFromUrl( if (id) { return { - type: 'giphy_gif', + type: 'gif', playerUri: `https://i.giphy.com/media/${id}/giphy.gif`, } } @@ -204,12 +203,12 @@ export function parseEmbedPlayerFromUrl( if (media === 'media') { if (idOrFilename === 'giphy.gif' || idOrFilename === 'giphy.gif') { return { - type: 'giphy_gif', + type: 'gif', playerUri: `https://i.giphy.com/media/${trackingOrId}/giphy.gif`, } } else if (filename === 'giphy.gif' || filename === 'giphy.gif') { return { - type: 'giphy_gif', + type: 'gif', playerUri: `https://i.giphy.com/media/${idOrFilename}/giphy.gif`, } } @@ -223,14 +222,14 @@ export function parseEmbedPlayerFromUrl( if (mediaOrFilename === 'media' && filename) { return { - type: 'giphy_gif', + type: 'gif', playerUri: `https://i.giphy.com/media/${ filename.split('.')[0] }/giphy.gif`, } } else if (mediaOrFilename) { return { - type: 'giphy_gif', + type: 'gif', playerUri: `https://i.giphy.com/media/${ mediaOrFilename.split('.')[0] }/giphy.gif`, @@ -244,7 +243,7 @@ export function parseEmbedPlayerFromUrl( if (parts.length === 4 && filename?.split('.').pop() === 'gif') { return { - type: 'tenor_gif', + type: 'gif', playerUri: url, } } @@ -257,7 +256,7 @@ export function parseEmbedPlayerFromUrl( const includesExt = filename.split('.').pop() === 'gif' return { - type: 'tenor_gif', + type: 'gif', playerUri: `${url}${!includesExt ? '.gif' : ''}`, } } @@ -271,7 +270,7 @@ export function parseEmbedPlayerFromUrl( if (ext === 'gif' || ext === 'webp') { return { - type: 'tenor_gif', + type: 'gif', playerUri: url, } } @@ -314,3 +313,11 @@ export function getPlayerHeight({ return width } } + +export function getGifHeight( + originalHeight: number, + originalWidth: number, + viewWidth: number, +) { + return (originalHeight / originalWidth) * viewWidth +} diff --git a/src/view/com/util/post-embeds/ExternalGifEmbed.tsx b/src/view/com/util/post-embeds/ExternalGifEmbed.tsx new file mode 100644 index 0000000000..23565ffd22 --- /dev/null +++ b/src/view/com/util/post-embeds/ExternalGifEmbed.tsx @@ -0,0 +1,124 @@ +import {EmbedPlayerParams, getGifHeight} from 'lib/strings/embed-player.ts' +import React from 'react' +import {Image, ImageLoadEventData} from 'expo-image' +import { + GestureResponderEvent, + LayoutChangeEvent, + Pressable, + StyleSheet, + View, +} from 'react-native' +import {isWeb} from 'platform/detection.ts' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' + +export function ExternalGifEmbed({ + thumb, + params, +}: { + thumb?: string + params: EmbedPlayerParams +}) { + const isThumbLoaded = React.useRef(false) + const viewWidth = React.useRef(0) + + const [isLoaded, setIsLoaded] = React.useState(false) + const [isAnimating, setIsAnimating] = React.useState(true) + const [height, setHeight] = React.useState(100) + + const imageRef = React.useRef(null) + + const onPlayPress = React.useCallback( + (event: GestureResponderEvent) => { + event.preventDefault() + + if (!isLoaded) { + setIsLoaded(true) + return + } + + if (isWeb) return + + setIsAnimating(prev => { + if (prev) { + imageRef.current?.stopAnimating() + return false + } else { + imageRef.current?.startAnimating() + return true + } + }) + }, + [isLoaded], + ) + + const onLoad = React.useCallback((e: ImageLoadEventData) => { + if (isThumbLoaded.current) return + + const scaledHeight = getGifHeight( + e.source.height, + e.source.width, + viewWidth.current, + ) + setHeight(scaledHeight > 300 ? 300 : scaledHeight) + }, []) + + const onLayout = React.useCallback((e: LayoutChangeEvent) => { + viewWidth.current = e.nativeEvent.layout.width + }, []) + + return ( + + {(!isLoaded || !isAnimating) && ( + + + + + + )} + + + ) +} + +const styles = StyleSheet.create({ + topRadius: { + borderTopLeftRadius: 6, + borderTopRightRadius: 6, + }, + layer: { + position: 'absolute', + top: 0, + left: 0, + right: 0, + bottom: 0, + }, + overlayContainer: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: 'rgba(0,0,0,0.5)', + }, + imageContainer: { + width: '100%', + overflow: 'hidden', + }, + overlayLayer: { + zIndex: 2, + }, +}) diff --git a/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx b/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx index 27aa804d35..bc8fdec092 100644 --- a/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx +++ b/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx @@ -8,6 +8,7 @@ import {AppBskyEmbedExternal} from '@atproto/api' import {toNiceDomain} from 'lib/strings/url-helpers' import {parseEmbedPlayerFromUrl} from 'lib/strings/embed-player' import {ExternalPlayer} from 'view/com/util/post-embeds/ExternalPlayerEmbed' +import {ExternalGifEmbed} from 'view/com/util/post-embeds/ExternalGifEmbed.tsx' export const ExternalLinkEmbed = ({ link, @@ -53,9 +54,12 @@ export const ExternalLinkEmbed = ({ /> ) : undefined} - {embedPlayerParams && ( + {(embedPlayerParams && embedPlayerParams.type !== 'gif' && ( - )} + )) || + (embedPlayerParams && embedPlayerParams.type === 'gif' && ( + + ))} )} -