From 4966b2152eb213bac34cbcb0ff01c246b7746f5c Mon Sep 17 00:00:00 2001
From: Paul Frazee <pfrazee@gmail.com>
Date: Wed, 14 Dec 2022 15:35:15 -0600
Subject: Add post embeds (images and external links)

---
 src/view/com/util/PostEmbeds.tsx | 180 ++++++++++++++++++++++++++++-----------
 1 file changed, 131 insertions(+), 49 deletions(-)

(limited to 'src/view/com/util/PostEmbeds.tsx')

diff --git a/src/view/com/util/PostEmbeds.tsx b/src/view/com/util/PostEmbeds.tsx
index 1591c658a..ea15dc9ca 100644
--- a/src/view/com/util/PostEmbeds.tsx
+++ b/src/view/com/util/PostEmbeds.tsx
@@ -1,88 +1,170 @@
 import React, {useEffect, useState} from 'react'
 import {
   ActivityIndicator,
+  Image,
+  ImageStyle,
   StyleSheet,
   StyleProp,
   Text,
+  TouchableWithoutFeedback,
   View,
   ViewStyle,
 } from 'react-native'
-import {Entity} from '../../../third-party/api/src/client/types/app/bsky/feed/post'
+import {
+  Record as PostRecord,
+  Entity,
+} from '../../../third-party/api/src/client/types/app/bsky/feed/post'
+import * as AppBskyEmbedImages from '../../../third-party/api/src/client/types/app/bsky/embed/images'
+import * as AppBskyEmbedExternal from '../../../third-party/api/src/client/types/app/bsky/embed/external'
 import {Link} from '../util/Link'
 import {LinkMeta, getLikelyType, LikelyType} from '../../../lib/link-meta'
 import {colors} from '../../lib/styles'
-import {useStores} from '../../../state'
+import {AutoSizedImage} from './images/AutoSizedImage'
+
+type Embed =
+  | AppBskyEmbedImages.Presented
+  | AppBskyEmbedExternal.Presented
+  | {$type: string; [k: string]: unknown}
 
 export function PostEmbeds({
-  entities,
+  embed,
   style,
 }: {
-  entities?: Entity[]
+  embed?: Embed
   style?: StyleProp<ViewStyle>
 }) {
-  const store = useStores()
-  const [linkMeta, setLinkMeta] = useState<LinkMeta | undefined>(undefined)
-  const link = entities?.find(
-    ent =>
-      ent.type === 'link' && getLikelyType(ent.value || '') === LikelyType.HTML,
-  )
-
-  useEffect(() => {
-    let aborted = false
-    store.linkMetas.getLinkMeta(link?.value || '').then(linkMeta => {
-      if (!aborted) {
-        setLinkMeta(linkMeta)
+  if (embed?.$type === 'app.bsky.embed.images#presented') {
+    const imgEmbed = embed as AppBskyEmbedImages.Presented
+    if (imgEmbed.images.length > 0) {
+      const Thumb = ({i, style}: {i: number; style: StyleProp<ImageStyle>}) => (
+        <AutoSizedImage
+          style={style}
+          uri={imgEmbed.images[i].thumb}
+          fullSizeUri={imgEmbed.images[i].fullsize}
+        />
+      )
+      if (imgEmbed.images.length === 4) {
+        return (
+          <View style={styles.imagesContainer}>
+            <View style={styles.imagePair}>
+              <Thumb i={0} style={styles.imagePairItem} />
+              <View style={styles.imagesWidthSpacer} />
+              <Thumb i={1} style={styles.imagePairItem} />
+            </View>
+            <View style={styles.imagesHeightSpacer} />
+            <View style={styles.imagePair}>
+              <Thumb i={2} style={styles.imagePairItem} />
+              <View style={styles.imagesWidthSpacer} />
+              <Thumb i={3} style={styles.imagePairItem} />
+            </View>
+          </View>
+        )
+      } else if (imgEmbed.images.length === 3) {
+        return (
+          <View style={styles.imagesContainer}>
+            <View style={styles.imageWide}>
+              <Thumb i={0} style={styles.imageWideItem} />
+            </View>
+            <View style={styles.imagesHeightSpacer} />
+            <View style={styles.imagePair}>
+              <Thumb i={1} style={styles.imagePairItem} />
+              <View style={styles.imagesWidthSpacer} />
+              <Thumb i={2} style={styles.imagePairItem} />
+            </View>
+          </View>
+        )
+      } else if (imgEmbed.images.length === 2) {
+        return (
+          <View style={styles.imagesContainer}>
+            <View style={styles.imagePair}>
+              <Thumb i={0} style={styles.imagePairItem} />
+              <View style={styles.imagesWidthSpacer} />
+              <Thumb i={1} style={styles.imagePairItem} />
+            </View>
+          </View>
+        )
+      } else {
+        return (
+          <View style={styles.imagesContainer}>
+            <View style={styles.imageBig}>
+              <Thumb i={0} style={styles.imageBigItem} />
+            </View>
+          </View>
+        )
       }
-    })
-
-    return () => {
-      aborted = true
     }
-  }, [link])
-
-  if (!link) {
-    return <View />
   }
-
-  return (
-    <Link style={[styles.outer, style]} href={link.value}>
-      {linkMeta ? (
-        <>
-          <Text numberOfLines={1} style={styles.title}>
-            {linkMeta.title || linkMeta.url}
-          </Text>
-          <Text numberOfLines={1} style={styles.url}>
-            {linkMeta.url}
+  if (embed?.$type === 'app.bsky.embed.external#presented') {
+    const externalEmbed = embed as AppBskyEmbedExternal.Presented
+    const link = externalEmbed.external
+    return (
+      <Link style={[styles.extOuter, style]} href={link.uri}>
+        {link.thumb ? (
+          <AutoSizedImage style={style} uri={link.thumb} />
+        ) : undefined}
+        <Text numberOfLines={1} style={styles.extTitle}>
+          {link.title || link.uri}
+        </Text>
+        <Text numberOfLines={1} style={styles.extUrl}>
+          {link.uri}
+        </Text>
+        {link.description ? (
+          <Text numberOfLines={2} style={styles.extDescription}>
+            {link.description}
           </Text>
-          {linkMeta.description ? (
-            <Text numberOfLines={2} style={styles.description}>
-              {linkMeta.description}
-            </Text>
-          ) : undefined}
-        </>
-      ) : (
-        <ActivityIndicator />
-      )}
-    </Link>
-  )
+        ) : undefined}
+      </Link>
+    )
+  }
+  return <View />
 }
 
 const styles = StyleSheet.create({
-  outer: {
+  imagesContainer: {
+    marginBottom: 20,
+  },
+  imagesWidthSpacer: {
+    width: 5,
+  },
+  imagesHeightSpacer: {
+    height: 5,
+  },
+  imagePair: {
+    flexDirection: 'row',
+  },
+  imagePairItem: {
+    resizeMode: 'contain',
+    flex: 1,
+    borderRadius: 4,
+  },
+  imageWide: {},
+  imageWideItem: {
+    resizeMode: 'contain',
+    borderRadius: 4,
+  },
+  imageBig: {},
+  imageBigItem: {
+    borderRadius: 4,
+  },
+
+  extOuter: {
     borderWidth: 1,
     borderColor: colors.gray2,
     borderRadius: 8,
     padding: 10,
   },
-  title: {
+  extImage: {
+    // TODO
+  },
+  extTitle: {
     fontSize: 16,
     fontWeight: 'bold',
   },
-  description: {
+  extDescription: {
     marginTop: 4,
     fontSize: 15,
   },
-  url: {
+  extUrl: {
     color: colors.gray4,
   },
 })
-- 
cgit 1.4.1

