forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {memo, useMemo} from 'react'
2import {AtUri} from '@atproto/api'
3import {msg, Trans} from '@lingui/macro'
4import {useLingui} from '@lingui/react'
5import {useNavigation} from '@react-navigation/native'
6
7import {makeProfileLink} from '#/lib/routes/links'
8import {type NavigationProp} from '#/lib/routes/types'
9import {shareText, shareUrl} from '#/lib/sharing'
10import {toShareUrl} from '#/lib/strings/url-helpers'
11import {useProfileShadow} from '#/state/cache/profile-shadow'
12import {useSession} from '#/state/session'
13import {useBreakpoints} from '#/alf'
14import {useDialogControl} from '#/components/Dialog'
15import {EmbedDialog} from '#/components/dialogs/Embed'
16import {SendViaChatDialog} from '#/components/dms/dialogs/ShareViaChatDialog'
17import {ChainLink_Stroke2_Corner0_Rounded as ChainLinkIcon} from '#/components/icons/ChainLink'
18import {Clipboard_Stroke2_Corner2_Rounded as ClipboardIcon} from '#/components/icons/Clipboard'
19import {CodeBrackets_Stroke2_Corner0_Rounded as CodeBracketsIcon} from '#/components/icons/CodeBrackets'
20import {PaperPlane_Stroke2_Corner0_Rounded as Send} from '#/components/icons/PaperPlane'
21import * as Menu from '#/components/Menu'
22import {useAgeAssurance} from '#/ageAssurance'
23import {useAnalytics} from '#/analytics'
24import {IS_WEB} from '#/env'
25import {useDevMode} from '#/storage/hooks/dev-mode'
26import {type ShareMenuItemsProps} from './ShareMenuItems.types'
27
28let ShareMenuItems = ({
29 post,
30 record,
31 timestamp,
32 onShare: onShareProp,
33}: ShareMenuItemsProps): React.ReactNode => {
34 const ax = useAnalytics()
35 const {hasSession} = useSession()
36 const {gtMobile} = useBreakpoints()
37 const {_} = useLingui()
38 const navigation = useNavigation<NavigationProp>()
39 const embedPostControl = useDialogControl()
40 const sendViaChatControl = useDialogControl()
41 const [devModeEnabled] = useDevMode()
42 const aa = useAgeAssurance()
43
44 const postUri = post.uri
45 const postCid = post.cid
46 const postAuthor = useProfileShadow(post.author)
47
48 const href = useMemo(() => {
49 const urip = new AtUri(postUri)
50 return makeProfileLink(postAuthor, 'post', urip.rkey)
51 }, [postUri, postAuthor])
52
53 const hideInPWI = useMemo(() => {
54 return !!postAuthor.labels?.find(
55 label => label.val === '!no-unauthenticated',
56 )
57 }, [postAuthor])
58
59 const onCopyLink = () => {
60 ax.metric('share:press:copyLink', {})
61 const url = toShareUrl(href)
62 shareUrl(url)
63 onShareProp()
64 }
65
66 const onSelectChatToShareTo = (conversation: string) => {
67 ax.metric('share:press:dmSelected', {})
68 navigation.navigate('MessagesConversation', {
69 conversation,
70 embed: postUri,
71 })
72 }
73
74 const canEmbed = IS_WEB && gtMobile && !hideInPWI
75
76 const onShareATURI = () => {
77 shareText(postUri)
78 }
79
80 const onShareAuthorDID = () => {
81 shareText(postAuthor.did)
82 }
83
84 const copyLinkItem = (
85 <Menu.Item
86 testID="postDropdownShareBtn"
87 label={_(msg`Copy link to post`)}
88 onPress={onCopyLink}>
89 <Menu.ItemText>
90 <Trans>Copy link to post</Trans>
91 </Menu.ItemText>
92 <Menu.ItemIcon icon={ChainLinkIcon} position="right" />
93 </Menu.Item>
94 )
95
96 return (
97 <>
98 <Menu.Outer>
99 {!hideInPWI && copyLinkItem}
100
101 {hasSession && aa.state.access === aa.Access.Full && (
102 <Menu.Item
103 testID="postDropdownSendViaDMBtn"
104 label={_(msg`Send via direct message`)}
105 onPress={() => {
106 ax.metric('share:press:openDmSearch', {})
107 sendViaChatControl.open()
108 }}>
109 <Menu.ItemText>
110 <Trans>Send via direct message</Trans>
111 </Menu.ItemText>
112 <Menu.ItemIcon icon={Send} position="right" />
113 </Menu.Item>
114 )}
115
116 {canEmbed && (
117 <Menu.Item
118 testID="postDropdownEmbedBtn"
119 label={_(msg`Embed post`)}
120 onPress={() => {
121 ax.metric('share:press:embed', {})
122 embedPostControl.open()
123 }}>
124 <Menu.ItemText>{_(msg`Embed post`)}</Menu.ItemText>
125 <Menu.ItemIcon icon={CodeBracketsIcon} position="right" />
126 </Menu.Item>
127 )}
128
129 {hideInPWI && (
130 <>
131 {hasSession && <Menu.Divider />}
132 {copyLinkItem}
133 <Menu.LabelText style={{maxWidth: 220}}>
134 <Trans>Note: This post is only visible to logged-in users.</Trans>
135 </Menu.LabelText>
136 </>
137 )}
138
139 {devModeEnabled && (
140 <>
141 <Menu.Divider />
142 <Menu.Item
143 testID="postAtUriShareBtn"
144 label={_(msg`Copy post at:// URI`)}
145 onPress={onShareATURI}>
146 <Menu.ItemText>
147 <Trans>Copy post at:// URI</Trans>
148 </Menu.ItemText>
149 <Menu.ItemIcon icon={ClipboardIcon} position="right" />
150 </Menu.Item>
151 <Menu.Item
152 testID="postAuthorDIDShareBtn"
153 label={_(msg`Copy author DID`)}
154 onPress={onShareAuthorDID}>
155 <Menu.ItemText>
156 <Trans>Copy author DID</Trans>
157 </Menu.ItemText>
158 <Menu.ItemIcon icon={ClipboardIcon} position="right" />
159 </Menu.Item>
160 </>
161 )}
162 </Menu.Outer>
163
164 {canEmbed && (
165 <EmbedDialog
166 control={embedPostControl}
167 postCid={postCid}
168 postUri={postUri}
169 record={record}
170 postAuthor={postAuthor}
171 timestamp={timestamp}
172 />
173 )}
174
175 <SendViaChatDialog
176 control={sendViaChatControl}
177 onSelectChat={onSelectChatToShareTo}
178 />
179 </>
180 )
181}
182ShareMenuItems = memo(ShareMenuItems)
183export {ShareMenuItems}