about summary refs log tree commit diff
path: root/src/view/com/composer/ComposePost.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com/composer/ComposePost.tsx')
-rw-r--r--src/view/com/composer/ComposePost.tsx82
1 files changed, 81 insertions, 1 deletions
diff --git a/src/view/com/composer/ComposePost.tsx b/src/view/com/composer/ComposePost.tsx
index abdcd04ec..6a959d41e 100644
--- a/src/view/com/composer/ComposePost.tsx
+++ b/src/view/com/composer/ComposePost.tsx
@@ -16,6 +16,7 @@ import LinearGradient from 'react-native-linear-gradient'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {UserAutocompleteViewModel} from '../../../state/models/user-autocomplete-view'
 import {Autocomplete} from './Autocomplete'
+import {ExternalEmbed} from './ExternalEmbed'
 import {Text} from '../util/text/Text'
 import * as Toast from '../util/Toast'
 // @ts-ignore no type definition -prf
@@ -28,7 +29,9 @@ import {useStores} from '../../../state'
 import * as apilib from '../../../state/lib/api'
 import {ComposerOpts} from '../../../state/models/shell-ui'
 import {s, colors, gradients} from '../../lib/styles'
-import {detectLinkables} from '../../../lib/strings'
+import {detectLinkables, extractEntities} from '../../../lib/strings'
+import {getLinkMeta} from '../../../lib/link-meta'
+import {downloadAndResize} from '../../../lib/images'
 import {UserLocalPhotosModel} from '../../../state/models/user-local-photos'
 import {PhotoCarouselPicker} from './PhotoCarouselPicker'
 import {SelectedPhoto} from './SelectedPhoto'
@@ -56,6 +59,10 @@ export const ComposePost = observer(function ComposePost({
   const [processingState, setProcessingState] = useState('')
   const [error, setError] = useState('')
   const [text, setText] = useState('')
+  const [extLink, setExtLink] = useState<apilib.ExternalEmbedDraft | undefined>(
+    undefined,
+  )
+  const [attemptedExtLinks, setAttemptedExtLinks] = useState<string[]>([])
   const [isSelectingPhotos, setIsSelectingPhotos] = useState(
     imagesOpen || false,
   )
@@ -71,11 +78,61 @@ export const ComposePost = observer(function ComposePost({
     [store],
   )
 
+  // initial setup
   useEffect(() => {
     autocompleteView.setup()
     localPhotos.setup()
   }, [autocompleteView, localPhotos])
 
+  // external link metadata-fetch flow
+  useEffect(() => {
+    let aborted = false
+    const cleanup = () => {
+      aborted = true
+    }
+    if (!extLink) {
+      return cleanup
+    }
+    if (!extLink.meta) {
+      getLinkMeta(extLink.uri).then(meta => {
+        if (aborted) {
+          return
+        }
+        setExtLink({
+          uri: extLink.uri,
+          isLoading: !!meta.image,
+          meta,
+        })
+      })
+      return cleanup
+    }
+    if (extLink.isLoading && extLink.meta?.image && !extLink.localThumb) {
+      downloadAndResize({
+        uri: extLink.meta.image,
+        width: 250,
+        height: 250,
+        mode: 'contain',
+        maxSize: 100000,
+        timeout: 15e3,
+      })
+        .catch(() => undefined)
+        .then(localThumb => {
+          setExtLink({
+            ...extLink,
+            isLoading: false, // done
+            localThumb,
+          })
+        })
+      return cleanup
+    }
+    if (extLink.isLoading) {
+      setExtLink({
+        ...extLink,
+        isLoading: false, // done
+      })
+    }
+  }, [extLink])
+
   useEffect(() => {
     // HACK
     // wait a moment before focusing the input to resolve some layout bugs with the keyboard-avoiding-view
@@ -119,6 +176,22 @@ export const ComposePost = observer(function ComposePost({
     } else {
       autocompleteView.setActive(false)
     }
+
+    if (!extLink && /\s$/.test(newText)) {
+      const ents = extractEntities(newText)
+      const entLink = ents
+        ?.filter(
+          ent => ent.type === 'link' && !attemptedExtLinks.includes(ent.value),
+        )
+        .pop() // use last
+      if (entLink) {
+        setExtLink({
+          uri: entLink.value,
+          isLoading: true,
+        })
+        setAttemptedExtLinks([...attemptedExtLinks, entLink.value])
+      }
+    }
   }
   const onPressCancel = () => {
     onClose()
@@ -141,6 +214,7 @@ export const ComposePost = observer(function ComposePost({
         store,
         text,
         replyTo?.uri,
+        extLink,
         selectedPhotos,
         autocompleteView.knownHandles,
         setProcessingState,
@@ -297,6 +371,12 @@ export const ComposePost = observer(function ComposePost({
               selectedPhotos={selectedPhotos}
               onSelectPhotos={onSelectPhotos}
             />
+            {!selectedPhotos.length && extLink && (
+              <ExternalEmbed
+                link={extLink}
+                onRemove={() => setExtLink(undefined)}
+              />
+            )}
           </ScrollView>
           {isSelectingPhotos &&
             localPhotos.photos != null &&