From c3f88e0a48bdf22831736ad3d44222e7c4418486 Mon Sep 17 00:00:00 2001
From: Samuel Newman <mozzius@protonmail.com>
Date: Sat, 24 May 2025 02:02:38 +0300
Subject: Share menu (#7840)

* move post ctrls to #/components

* restructure post controls, basic share menu

* add border radius to searchable people list for android

* Revert "add border radius to searchable people list for android"

This reverts commit 417449086e25b82f5683b12f6405d972f48ce50e.

* add copy link to native share menu

* reorg files again

* open native share menu on long press

* Translation comments

Thanks @surfdude29

* abs path

* update type imports, remove forwardRef

* rm react import

* equal spacing of buttons, extract disco debug

* add better icon

* add right offset to share button for visual alignment

* Add recent chats to share menu (#7853)

* add recent chats to share menu

* Update RecentChats.tsx

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update RecentChats.tsx

* add fading edge on andriod

* tweak scrollview

* Add metrics and A/B alt icon to share menu (#8401)

* add metrics

* add a/b tested alt icon

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* More descriptive share text/icon on web (#7854)

* more descriptive share text on web

* revert dev mode changes

* add missing import

* use modified share icon everywhere

* Add back conflicting changes

---------

Co-authored-by: Eric Bailey <git@esb.lol>

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
Co-authored-by: Eric Bailey <git@esb.lol>
---
 .../PostControls/ShareMenu/ShareMenuItems.web.tsx  | 192 +++++++++++++++++++++
 1 file changed, 192 insertions(+)
 create mode 100644 src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx

(limited to 'src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx')

diff --git a/src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx b/src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx
new file mode 100644
index 000000000..0da259678
--- /dev/null
+++ b/src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx
@@ -0,0 +1,192 @@
+import {memo, useMemo} from 'react'
+import {AtUri} from '@atproto/api'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+import {useNavigation} from '@react-navigation/native'
+import type React from 'react'
+
+import {makeProfileLink} from '#/lib/routes/links'
+import {type NavigationProp} from '#/lib/routes/types'
+import {shareText, shareUrl} from '#/lib/sharing'
+import {toShareUrl} from '#/lib/strings/url-helpers'
+import {logger} from '#/logger'
+import {isWeb} from '#/platform/detection'
+import {useProfileShadow} from '#/state/cache/profile-shadow'
+import {useSession} from '#/state/session'
+import {useBreakpoints} from '#/alf'
+import {useDialogControl} from '#/components/Dialog'
+import {EmbedDialog} from '#/components/dialogs/Embed'
+import {SendViaChatDialog} from '#/components/dms/dialogs/ShareViaChatDialog'
+import {ChainLink_Stroke2_Corner0_Rounded as ChainLinkIcon} from '#/components/icons/ChainLink'
+import {Clipboard_Stroke2_Corner2_Rounded as ClipboardIcon} from '#/components/icons/Clipboard'
+import {CodeBrackets_Stroke2_Corner0_Rounded as CodeBracketsIcon} from '#/components/icons/CodeBrackets'
+import {PaperPlane_Stroke2_Corner0_Rounded as Send} from '#/components/icons/PaperPlane'
+import * as Menu from '#/components/Menu'
+import * as Prompt from '#/components/Prompt'
+import {useDevMode} from '#/storage/hooks/dev-mode'
+import {type ShareMenuItemsProps} from './ShareMenuItems.types'
+
+let ShareMenuItems = ({
+  post,
+  record,
+  timestamp,
+  onShare: onShareProp,
+}: ShareMenuItemsProps): React.ReactNode => {
+  const {hasSession, currentAccount} = useSession()
+  const {gtMobile} = useBreakpoints()
+  const {_} = useLingui()
+  const navigation = useNavigation<NavigationProp>()
+  const loggedOutWarningPromptControl = useDialogControl()
+  const embedPostControl = useDialogControl()
+  const sendViaChatControl = useDialogControl()
+  const [devModeEnabled] = useDevMode()
+
+  const postUri = post.uri
+  const postCid = post.cid
+  const postAuthor = useProfileShadow(post.author)
+
+  const href = useMemo(() => {
+    const urip = new AtUri(postUri)
+    return makeProfileLink(postAuthor, 'post', urip.rkey)
+  }, [postUri, postAuthor])
+
+  const hideInPWI = useMemo(() => {
+    return !!postAuthor.labels?.find(
+      label => label.val === '!no-unauthenticated',
+    )
+  }, [postAuthor])
+
+  const showLoggedOutWarning =
+    postAuthor.did !== currentAccount?.did && hideInPWI
+
+  const onCopyLink = () => {
+    logger.metric('share:press:copyLink', {}, {statsig: true})
+    const url = toShareUrl(href)
+    shareUrl(url)
+    onShareProp()
+  }
+
+  const onSelectChatToShareTo = (conversation: string) => {
+    logger.metric('share:press:dmSelected', {}, {statsig: true})
+    navigation.navigate('MessagesConversation', {
+      conversation,
+      embed: postUri,
+    })
+  }
+
+  const canEmbed = isWeb && gtMobile && !hideInPWI
+
+  const onShareATURI = () => {
+    shareText(postUri)
+  }
+
+  const onShareAuthorDID = () => {
+    shareText(postAuthor.did)
+  }
+
+  return (
+    <>
+      <Menu.Outer>
+        <Menu.Group>
+          <Menu.Item
+            testID="postDropdownShareBtn"
+            label={_(msg`Copy link to post`)}
+            onPress={() => {
+              if (showLoggedOutWarning) {
+                loggedOutWarningPromptControl.open()
+              } else {
+                onCopyLink()
+              }
+            }}>
+            <Menu.ItemText>
+              <Trans>Copy link to post</Trans>
+            </Menu.ItemText>
+            <Menu.ItemIcon icon={ChainLinkIcon} position="right" />
+          </Menu.Item>
+
+          {hasSession && (
+            <Menu.Item
+              testID="postDropdownSendViaDMBtn"
+              label={_(msg`Send via direct message`)}
+              onPress={() => {
+                logger.metric('share:press:openDmSearch', {}, {statsig: true})
+                sendViaChatControl.open()
+              }}>
+              <Menu.ItemText>
+                <Trans>Send via direct message</Trans>
+              </Menu.ItemText>
+              <Menu.ItemIcon icon={Send} position="right" />
+            </Menu.Item>
+          )}
+
+          {canEmbed && (
+            <Menu.Item
+              testID="postDropdownEmbedBtn"
+              label={_(msg`Embed post`)}
+              onPress={() => {
+                logger.metric('share:press:embed', {}, {statsig: true})
+                embedPostControl.open()
+              }}>
+              <Menu.ItemText>{_(msg`Embed post`)}</Menu.ItemText>
+              <Menu.ItemIcon icon={CodeBracketsIcon} position="right" />
+            </Menu.Item>
+          )}
+        </Menu.Group>
+
+        {devModeEnabled && (
+          <>
+            <Menu.Divider />
+            <Menu.Group>
+              <Menu.Item
+                testID="postAtUriShareBtn"
+                label={_(msg`Copy post at:// URI`)}
+                onPress={onShareATURI}>
+                <Menu.ItemText>
+                  <Trans>Copy post at:// URI</Trans>
+                </Menu.ItemText>
+                <Menu.ItemIcon icon={ClipboardIcon} position="right" />
+              </Menu.Item>
+              <Menu.Item
+                testID="postAuthorDIDShareBtn"
+                label={_(msg`Copy author DID`)}
+                onPress={onShareAuthorDID}>
+                <Menu.ItemText>
+                  <Trans>Copy author DID</Trans>
+                </Menu.ItemText>
+                <Menu.ItemIcon icon={ClipboardIcon} position="right" />
+              </Menu.Item>
+            </Menu.Group>
+          </>
+        )}
+      </Menu.Outer>
+
+      <Prompt.Basic
+        control={loggedOutWarningPromptControl}
+        title={_(msg`Note about sharing`)}
+        description={_(
+          msg`This post is only visible to logged-in users. It won't be visible to people who aren't signed in.`,
+        )}
+        onConfirm={onCopyLink}
+        confirmButtonCta={_(msg`Share anyway`)}
+      />
+
+      {canEmbed && (
+        <EmbedDialog
+          control={embedPostControl}
+          postCid={postCid}
+          postUri={postUri}
+          record={record}
+          postAuthor={postAuthor}
+          timestamp={timestamp}
+        />
+      )}
+
+      <SendViaChatDialog
+        control={sendViaChatControl}
+        onSelectChat={onSelectChatToShareTo}
+      />
+    </>
+  )
+}
+ShareMenuItems = memo(ShareMenuItems)
+export {ShareMenuItems}
-- 
cgit 1.4.1

