about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/extractBskyMeta.ts99
-rw-r--r--src/lib/link-meta.ts20
-rw-r--r--src/state/models/link-metas-view.ts2
-rw-r--r--src/view/com/composer/ComposePost.tsx2
-rw-r--r--src/view/com/profile/ProfileHeader.tsx9
-rw-r--r--src/view/com/util/PostEmbeds.tsx2
6 files changed, 113 insertions, 21 deletions
diff --git a/src/lib/extractBskyMeta.ts b/src/lib/extractBskyMeta.ts
new file mode 100644
index 000000000..e53036aec
--- /dev/null
+++ b/src/lib/extractBskyMeta.ts
@@ -0,0 +1,99 @@
+import {LikelyType, LinkMeta} from './link-meta'
+import {match as matchRoute} from '../view/routes'
+import {convertBskyAppUrlIfNeeded, makeRecordUri} from './strings'
+import {RootStoreModel} from '../state'
+import {PostThreadViewModel} from '../state/models/post-thread-view'
+
+import {Home} from '../view/screens/Home'
+import {Search} from '../view/screens/Search'
+import {Notifications} from '../view/screens/Notifications'
+import {PostThread} from '../view/screens/PostThread'
+import {PostUpvotedBy} from '../view/screens/PostUpvotedBy'
+import {PostRepostedBy} from '../view/screens/PostRepostedBy'
+import {Profile} from '../view/screens/Profile'
+import {ProfileFollowers} from '../view/screens/ProfileFollowers'
+import {ProfileFollows} from '../view/screens/ProfileFollows'
+
+// NOTE
+// this is a hack around the lack of hosted social metadata
+// remove once that's implemented
+// -prf
+export async function extractBskyMeta(
+  store: RootStoreModel,
+  url: string,
+): Promise<LinkMeta> {
+  url = convertBskyAppUrlIfNeeded(url)
+  const route = matchRoute(url)
+  let meta: LinkMeta = {
+    likelyType: LikelyType.AtpData,
+    url,
+    title: route.defaultTitle,
+  }
+
+  if (route.Com === Home) {
+    meta = {
+      ...meta,
+      title: 'Bluesky',
+      description: 'A new kind of social network',
+    }
+  } else if (route.Com === Search) {
+    meta = {
+      ...meta,
+      title: 'Search - Bluesky',
+      description: 'A new kind of social network',
+    }
+  } else if (route.Com === Notifications) {
+    meta = {
+      ...meta,
+      title: 'Notifications - Bluesky',
+      description: 'A new kind of social network',
+    }
+  } else if (
+    route.Com === PostThread ||
+    route.Com === PostUpvotedBy ||
+    route.Com === PostRepostedBy
+  ) {
+    // post and post-related screens
+    const threadUri = makeRecordUri(
+      route.params.name,
+      'app.bsky.feed.post',
+      route.params.rkey,
+    )
+    const threadView = new PostThreadViewModel(store, {
+      uri: threadUri,
+      depth: 0,
+    })
+    await threadView.setup().catch(_err => undefined)
+    const title = [
+      route.Com === PostUpvotedBy
+        ? 'Likes on a post by'
+        : route.Com === PostRepostedBy
+        ? 'Reposts of a post by'
+        : 'Post by',
+      threadView.thread?.post.author.displayName ||
+        threadView.thread?.post.author.handle ||
+        'a bluesky user',
+    ].join(' ')
+    meta = {
+      ...meta,
+      title,
+      description: threadView.thread?.postRecord?.text,
+    }
+  } else if (
+    route.Com === Profile ||
+    route.Com === ProfileFollowers ||
+    route.Com === ProfileFollows
+  ) {
+    // profile and profile-related screens
+    const profile = await store.profiles.getProfile(route.params.name)
+    if (profile?.data) {
+      meta = {
+        ...meta,
+        title: profile.data.displayName || profile.data.handle,
+        description: profile.data.description,
+      }
+    }
+  }
+
+  return meta
+}
diff --git a/src/lib/link-meta.ts b/src/lib/link-meta.ts
index 49e75cde2..9a0325c8f 100644
--- a/src/lib/link-meta.ts
+++ b/src/lib/link-meta.ts
@@ -1,10 +1,7 @@
 import he from 'he'
-import {
-  extractHtmlMeta,
-  isBskyAppUrl,
-  convertBskyAppUrlIfNeeded,
-} from './strings'
-import {match as matchRoute} from '../view/routes'
+import {extractHtmlMeta, isBskyAppUrl} from './strings'
+import {RootStoreModel} from '../state'
+import {extractBskyMeta} from './extractBskyMeta'
 
 export enum LikelyType {
   HTML,
@@ -26,19 +23,12 @@ export interface LinkMeta {
 }
 
 export async function getLinkMeta(
+  store: RootStoreModel,
   url: string,
   timeout = 5e3,
 ): Promise<LinkMeta> {
   if (isBskyAppUrl(url)) {
-    // TODO this could be better
-    url = convertBskyAppUrlIfNeeded(url)
-    const route = matchRoute(url)
-    return {
-      likelyType: LikelyType.AtpData,
-      url,
-      title: route.defaultTitle,
-      // description: ''
-    }
+    return extractBskyMeta(store, url)
   }
 
   let urlp
diff --git a/src/state/models/link-metas-view.ts b/src/state/models/link-metas-view.ts
index 0187f4260..6b787987d 100644
--- a/src/state/models/link-metas-view.ts
+++ b/src/state/models/link-metas-view.ts
@@ -31,7 +31,7 @@ export class LinkMetasViewModel {
       }
     }
     try {
-      const promise = getLinkMeta(url)
+      const promise = getLinkMeta(this.rootStore, url)
       this.cache.set(url, promise)
       const res = await promise
       this.cache.set(url, res)
diff --git a/src/view/com/composer/ComposePost.tsx b/src/view/com/composer/ComposePost.tsx
index 228b11035..a8def6405 100644
--- a/src/view/com/composer/ComposePost.tsx
+++ b/src/view/com/composer/ComposePost.tsx
@@ -94,7 +94,7 @@ export const ComposePost = observer(function ComposePost({
       return cleanup
     }
     if (!extLink.meta) {
-      getLinkMeta(extLink.uri).then(meta => {
+      getLinkMeta(store, extLink.uri).then(meta => {
         if (aborted) {
           return
         }
diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx
index 3982637fc..c14a5c827 100644
--- a/src/view/com/profile/ProfileHeader.tsx
+++ b/src/view/com/profile/ProfileHeader.tsx
@@ -1,6 +1,7 @@
 import React from 'react'
 import {observer} from 'mobx-react-lite'
 import {
+  Share,
   StyleSheet,
   TouchableOpacity,
   TouchableWithoutFeedback,
@@ -16,7 +17,7 @@ import {
   ReportAccountModal,
   ProfileImageLightbox,
 } from '../../../state/models/shell-ui'
-import {pluralize} from '../../../lib/strings'
+import {pluralize, toShareUrl} from '../../../lib/strings'
 import {s, gradients} from '../../lib/styles'
 import {DropdownButton, DropdownItem} from '../util/forms/DropdownButton'
 import * as Toast from '../util/Toast'
@@ -66,6 +67,9 @@ export const ProfileHeader = observer(function ProfileHeader({
   const onPressFollows = () => {
     store.nav.navigate(`/profile/${view.handle}/follows`)
   }
+  const onPressShare = () => {
+    Share.share({url: toShareUrl(`/profile/${view.handle}`)})
+  }
   const onPressMuteAccount = async () => {
     try {
       await view.muteAccount()
@@ -133,9 +137,8 @@ export const ProfileHeader = observer(function ProfileHeader({
   // loaded
   // =
   const isMe = store.me.did === view.did
-  let dropdownItems: DropdownItem[] | undefined
+  let dropdownItems: DropdownItem[] = [{label: 'Share', onPress: onPressShare}]
   if (!isMe) {
-    dropdownItems = dropdownItems || []
     dropdownItems.push({
       label: view.myState.muted ? 'Unmute Account' : 'Mute Account',
       onPress: view.myState.muted ? onPressUnmuteAccount : onPressMuteAccount,
diff --git a/src/view/com/util/PostEmbeds.tsx b/src/view/com/util/PostEmbeds.tsx
index 3fb93ed48..65518470a 100644
--- a/src/view/com/util/PostEmbeds.tsx
+++ b/src/view/com/util/PostEmbeds.tsx
@@ -92,7 +92,7 @@ export function PostEmbeds({
           />
         )}
         <View style={styles.extInner}>
-          <Text type="sm-bold" numberOfLines={2} style={[pal.text]}>
+          <Text type="md-bold" numberOfLines={2} style={[pal.text]}>
             {link.title || link.uri}
           </Text>
           <Text