GIF previews in notifications (#4447)
* gifs in notifications * remove try/catch * Limit try/catch scope --------- Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
This commit is contained in:
		
							parent
							
								
									7ddbc392c3
								
							
						
					
					
						commit
						3dc34be929
					
				
					 3 changed files with 143 additions and 59 deletions
				
			
		| 
						 | 
				
			
			@ -8,6 +8,7 @@ import {
 | 
			
		|||
} from 'react-native'
 | 
			
		||||
import {
 | 
			
		||||
  AppBskyActorDefs,
 | 
			
		||||
  AppBskyEmbedExternal,
 | 
			
		||||
  AppBskyEmbedImages,
 | 
			
		||||
  AppBskyEmbedRecordWithMedia,
 | 
			
		||||
  AppBskyFeedDefs,
 | 
			
		||||
| 
						 | 
				
			
			@ -51,6 +52,7 @@ import {TimeElapsed} from '../util/TimeElapsed'
 | 
			
		|||
import {PreviewableUserAvatar, UserAvatar} from '../util/UserAvatar'
 | 
			
		||||
 | 
			
		||||
import hairlineWidth = StyleSheet.hairlineWidth
 | 
			
		||||
import {parseTenorGif} from '#/lib/strings/embed-player'
 | 
			
		||||
 | 
			
		||||
const MAX_AUTHORS = 5
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -465,17 +467,48 @@ function AdditionalPostText({post}: {post?: AppBskyFeedDefs.PostView}) {
 | 
			
		|||
  const pal = usePalette('default')
 | 
			
		||||
  if (post && AppBskyFeedPost.isRecord(post?.record)) {
 | 
			
		||||
    const text = post.record.text
 | 
			
		||||
    const images = AppBskyEmbedImages.isView(post.embed)
 | 
			
		||||
      ? post.embed.images
 | 
			
		||||
      : AppBskyEmbedRecordWithMedia.isView(post.embed) &&
 | 
			
		||||
        AppBskyEmbedImages.isView(post.embed.media)
 | 
			
		||||
      ? post.embed.media.images
 | 
			
		||||
      : undefined
 | 
			
		||||
    let images
 | 
			
		||||
    let isGif = false
 | 
			
		||||
 | 
			
		||||
    if (AppBskyEmbedImages.isView(post.embed)) {
 | 
			
		||||
      images = post.embed.images
 | 
			
		||||
    } else if (
 | 
			
		||||
      AppBskyEmbedRecordWithMedia.isView(post.embed) &&
 | 
			
		||||
      AppBskyEmbedImages.isView(post.embed.media)
 | 
			
		||||
    ) {
 | 
			
		||||
      images = post.embed.media.images
 | 
			
		||||
    } else if (
 | 
			
		||||
      AppBskyEmbedExternal.isView(post.embed) &&
 | 
			
		||||
      post.embed.external.thumb
 | 
			
		||||
    ) {
 | 
			
		||||
      let url: URL | undefined
 | 
			
		||||
      try {
 | 
			
		||||
        url = new URL(post.embed.external.uri)
 | 
			
		||||
      } catch {}
 | 
			
		||||
      if (url) {
 | 
			
		||||
        const {success} = parseTenorGif(url)
 | 
			
		||||
        if (success) {
 | 
			
		||||
          isGif = true
 | 
			
		||||
          images = [
 | 
			
		||||
            {
 | 
			
		||||
              thumb: post.embed.external.thumb,
 | 
			
		||||
              alt: post.embed.external.title,
 | 
			
		||||
              fullsize: post.embed.external.thumb,
 | 
			
		||||
            },
 | 
			
		||||
          ]
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <>
 | 
			
		||||
        {text?.length > 0 && <Text style={pal.textLight}>{text}</Text>}
 | 
			
		||||
        {images && images.length > 0 && (
 | 
			
		||||
          <ImageHorzList images={images} style={styles.additionalPostImages} />
 | 
			
		||||
          <ImageHorzList
 | 
			
		||||
            images={images}
 | 
			
		||||
            style={styles.additionalPostImages}
 | 
			
		||||
            gif={isGif}
 | 
			
		||||
          />
 | 
			
		||||
        )}
 | 
			
		||||
      </>
 | 
			
		||||
    )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,39 +2,60 @@ import React from 'react'
 | 
			
		|||
import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
 | 
			
		||||
import {Image} from 'expo-image'
 | 
			
		||||
import {AppBskyEmbedImages} from '@atproto/api'
 | 
			
		||||
import {Trans} from '@lingui/macro'
 | 
			
		||||
 | 
			
		||||
import {atoms as a} from '#/alf'
 | 
			
		||||
import {Text} from '#/components/Typography'
 | 
			
		||||
 | 
			
		||||
interface Props {
 | 
			
		||||
  images: AppBskyEmbedImages.ViewImage[]
 | 
			
		||||
  style?: StyleProp<ViewStyle>
 | 
			
		||||
  gif?: boolean
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function ImageHorzList({images, style}: Props) {
 | 
			
		||||
export function ImageHorzList({images, style, gif}: Props) {
 | 
			
		||||
  return (
 | 
			
		||||
    <View style={[styles.flexRow, style]}>
 | 
			
		||||
    <View style={[a.flex_row, a.gap_xs, style]}>
 | 
			
		||||
      {images.map(({thumb, alt}) => (
 | 
			
		||||
        <Image
 | 
			
		||||
        <View
 | 
			
		||||
          key={thumb}
 | 
			
		||||
          source={{uri: thumb}}
 | 
			
		||||
          style={styles.image}
 | 
			
		||||
          accessible={true}
 | 
			
		||||
          accessibilityIgnoresInvertColors
 | 
			
		||||
          accessibilityHint={alt}
 | 
			
		||||
          accessibilityLabel=""
 | 
			
		||||
        />
 | 
			
		||||
          style={[a.relative, a.flex_1, {aspectRatio: 1, maxWidth: 100}]}>
 | 
			
		||||
          <Image
 | 
			
		||||
            key={thumb}
 | 
			
		||||
            source={{uri: thumb}}
 | 
			
		||||
            style={[a.flex_1, a.rounded_xs]}
 | 
			
		||||
            accessible={true}
 | 
			
		||||
            accessibilityIgnoresInvertColors
 | 
			
		||||
            accessibilityHint={alt}
 | 
			
		||||
            accessibilityLabel=""
 | 
			
		||||
          />
 | 
			
		||||
          {gif && (
 | 
			
		||||
            <View style={styles.altContainer}>
 | 
			
		||||
              <Text style={styles.alt}>
 | 
			
		||||
                <Trans>GIF</Trans>
 | 
			
		||||
              </Text>
 | 
			
		||||
            </View>
 | 
			
		||||
          )}
 | 
			
		||||
        </View>
 | 
			
		||||
      ))}
 | 
			
		||||
    </View>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const styles = StyleSheet.create({
 | 
			
		||||
  flexRow: {
 | 
			
		||||
    flexDirection: 'row',
 | 
			
		||||
    gap: 5,
 | 
			
		||||
  altContainer: {
 | 
			
		||||
    backgroundColor: 'rgba(0, 0, 0, 0.75)',
 | 
			
		||||
    borderRadius: 6,
 | 
			
		||||
    paddingHorizontal: 6,
 | 
			
		||||
    paddingVertical: 3,
 | 
			
		||||
    position: 'absolute',
 | 
			
		||||
    right: 5,
 | 
			
		||||
    bottom: 5,
 | 
			
		||||
    zIndex: 2,
 | 
			
		||||
  },
 | 
			
		||||
  image: {
 | 
			
		||||
    maxWidth: 100,
 | 
			
		||||
    aspectRatio: 1,
 | 
			
		||||
    flex: 1,
 | 
			
		||||
    borderRadius: 4,
 | 
			
		||||
  alt: {
 | 
			
		||||
    color: 'white',
 | 
			
		||||
    fontSize: 7,
 | 
			
		||||
    fontWeight: 'bold',
 | 
			
		||||
  },
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue