Bluesky app fork with some witchin' additions 馃挮
at main 246 lines 7.9 kB view raw
1import {memo, useMemo} from 'react' 2import {AtUri} from '@atproto/api' 3import {msg} from '@lingui/core/macro' 4import {useLingui} from '@lingui/react' 5import {Trans} from '@lingui/react/macro' 6import {useNavigation} from '@react-navigation/native' 7 8import {useOpenLink} from '#/lib/hooks/useOpenLink' 9import {makeProfileLink} from '#/lib/routes/links' 10import {type NavigationProp} from '#/lib/routes/types' 11import {shareText, shareUrl} from '#/lib/sharing' 12import {toShareUrl, toShareUrlBsky} from '#/lib/strings/url-helpers' 13import {useProfileShadow} from '#/state/cache/profile-shadow' 14import {useShowExternalShareButtons} from '#/state/preferences/external-share-buttons' 15import {useSession} from '#/state/session' 16import {useBreakpoints} from '#/alf' 17import {useDialogControl} from '#/components/Dialog' 18import {EmbedDialog} from '#/components/dialogs/Embed' 19import {SendViaChatDialog} from '#/components/dms/dialogs/ShareViaChatDialog' 20import {ChainLink_Stroke2_Corner0_Rounded as ChainLinkIcon} from '#/components/icons/ChainLink' 21import {Clipboard_Stroke2_Corner2_Rounded as ClipboardIcon} from '#/components/icons/Clipboard' 22import {CodeBrackets_Stroke2_Corner0_Rounded as CodeBracketsIcon} from '#/components/icons/CodeBrackets' 23import {PaperPlane_Stroke2_Corner0_Rounded as Send} from '#/components/icons/PaperPlane' 24import {SquareArrowTopRight_Stroke2_Corner0_Rounded as ExternalIcon} from '#/components/icons/SquareArrowTopRight' 25import * as Menu from '#/components/Menu' 26import {useAgeAssurance} from '#/ageAssurance' 27import {useAnalytics} from '#/analytics' 28import {IS_WEB} from '#/env' 29import {useDevMode} from '#/storage/hooks/dev-mode' 30import {type ShareMenuItemsProps} from './ShareMenuItems.types' 31 32let ShareMenuItems = ({ 33 post, 34 record, 35 timestamp, 36 onShare: onShareProp, 37}: ShareMenuItemsProps): React.ReactNode => { 38 const ax = useAnalytics() 39 const {hasSession} = useSession() 40 const {gtMobile} = useBreakpoints() 41 const {_} = useLingui() 42 const navigation = useNavigation<NavigationProp>() 43 const embedPostControl = useDialogControl() 44 const sendViaChatControl = useDialogControl() 45 const [devModeEnabled] = useDevMode() 46 const aa = useAgeAssurance() 47 const openLink = useOpenLink() 48 49 const postUri = post.uri 50 const postCid = post.cid 51 const postAuthor = useProfileShadow(post.author) 52 53 const href = useMemo(() => { 54 const urip = new AtUri(postUri) 55 return makeProfileLink(postAuthor, 'post', urip.rkey) 56 }, [postUri, postAuthor]) 57 58 const hideInPWI = useMemo(() => { 59 return !!postAuthor.labels?.find( 60 label => label.val === '!no-unauthenticated', 61 ) 62 }, [postAuthor]) 63 64 const onCopyLink = () => { 65 ax.metric('share:press:copyLink', {}) 66 const url = toShareUrl(href) 67 shareUrl(url) 68 onShareProp() 69 } 70 71 const onCopyLinkBsky = () => { 72 ax.metric('share:press:copyLink', {}) 73 const url = toShareUrlBsky(href) 74 shareUrl(url) 75 onShareProp() 76 } 77 78 const onSelectChatToShareTo = (conversation: string) => { 79 ax.metric('share:press:dmSelected', {}) 80 navigation.navigate('MessagesConversation', { 81 conversation, 82 embed: postUri, 83 }) 84 } 85 86 const canEmbed = IS_WEB && gtMobile && !hideInPWI 87 88 const onShareATURI = () => { 89 shareText(postUri) 90 } 91 92 const onShareAuthorDID = () => { 93 shareText(postAuthor.did) 94 } 95 96 const showExternalShareButtons = useShowExternalShareButtons() 97 const isBridgedPost = 98 !!post.record.bridgyOriginalUrl || !!post.record.fediverseId 99 const originalPostUrl = (post.record.bridgyOriginalUrl || 100 post.record.fediverseId) as string | undefined 101 102 const onOpenOriginalPost = () => { 103 if (originalPostUrl) { 104 openLink(originalPostUrl, true) 105 } 106 } 107 108 const onOpenPostInPdsls = () => { 109 openLink(`https://pdsls.dev/${post.uri}`, true) 110 } 111 112 const copyLinkItem = ( 113 <Menu.Group> 114 <Menu.Item 115 testID="postDropdownShareBtn" 116 label={_(msg`Copy link to post`)} 117 onPress={onCopyLink}> 118 <Menu.ItemText> 119 <Trans>Copy link to post</Trans> 120 </Menu.ItemText> 121 <Menu.ItemIcon icon={ChainLinkIcon} position="right" /> 122 </Menu.Item> 123 <Menu.Item 124 testID="postDropdownShareBtn" 125 label={_(msg`Copy link to post`)} 126 onPress={onCopyLinkBsky}> 127 <Menu.ItemText> 128 <Trans>Copy via bsky.app</Trans> 129 </Menu.ItemText> 130 <Menu.ItemIcon icon={ChainLinkIcon} position="right" /> 131 </Menu.Item> 132 </Menu.Group> 133 ) 134 135 return ( 136 <> 137 <Menu.Outer> 138 {copyLinkItem} 139 140 {showExternalShareButtons && isBridgedPost && ( 141 <Menu.Item 142 testID="postDropdownOpenOriginalPost" 143 label={_(msg`Open original post`)} 144 onPress={onOpenOriginalPost}> 145 <Menu.ItemText> 146 <Trans>Open original post</Trans> 147 </Menu.ItemText> 148 <Menu.ItemIcon icon={ExternalIcon} position="right" /> 149 </Menu.Item> 150 )} 151 152 {showExternalShareButtons && ( 153 <Menu.Item 154 testID="postDropdownOpenInPdsls" 155 label={_(msg`Open post in PDSls`)} 156 onPress={onOpenPostInPdsls}> 157 <Menu.ItemText> 158 <Trans>Open post in PDSls</Trans> 159 </Menu.ItemText> 160 <Menu.ItemIcon icon={ExternalIcon} position="right" /> 161 </Menu.Item> 162 )} 163 164 {hasSession && aa.state.access === aa.Access.Full && ( 165 <Menu.Item 166 testID="postDropdownSendViaDMBtn" 167 label={_(msg`Send via direct message`)} 168 onPress={() => { 169 ax.metric('share:press:openDmSearch', {}) 170 sendViaChatControl.open() 171 }}> 172 <Menu.ItemText> 173 <Trans>Send via direct message</Trans> 174 </Menu.ItemText> 175 <Menu.ItemIcon icon={Send} position="right" /> 176 </Menu.Item> 177 )} 178 179 {canEmbed && ( 180 <Menu.Item 181 testID="postDropdownEmbedBtn" 182 label={_(msg`Embed post`)} 183 onPress={() => { 184 ax.metric('share:press:embed', {}) 185 embedPostControl.open() 186 }}> 187 <Menu.ItemText>{_(msg`Embed post`)}</Menu.ItemText> 188 <Menu.ItemIcon icon={CodeBracketsIcon} position="right" /> 189 </Menu.Item> 190 )} 191 192 {false && hideInPWI && ( 193 <> 194 {hasSession && <Menu.Divider />} 195 {copyLinkItem} 196 <Menu.LabelText style={{maxWidth: 220}}> 197 <Trans>Note: This post is only visible to logged-in users.</Trans> 198 </Menu.LabelText> 199 </> 200 )} 201 202 {devModeEnabled && ( 203 <> 204 <Menu.Divider /> 205 <Menu.Item 206 testID="postAtUriShareBtn" 207 label={_(msg`Copy post at:// URI`)} 208 onPress={onShareATURI}> 209 <Menu.ItemText> 210 <Trans>Copy post at:// URI</Trans> 211 </Menu.ItemText> 212 <Menu.ItemIcon icon={ClipboardIcon} position="right" /> 213 </Menu.Item> 214 <Menu.Item 215 testID="postAuthorDIDShareBtn" 216 label={_(msg`Copy author DID`)} 217 onPress={onShareAuthorDID}> 218 <Menu.ItemText> 219 <Trans>Copy author DID</Trans> 220 </Menu.ItemText> 221 <Menu.ItemIcon icon={ClipboardIcon} position="right" /> 222 </Menu.Item> 223 </> 224 )} 225 </Menu.Outer> 226 227 {canEmbed && ( 228 <EmbedDialog 229 control={embedPostControl} 230 postCid={postCid} 231 postUri={postUri} 232 record={record} 233 postAuthor={postAuthor} 234 timestamp={timestamp} 235 /> 236 )} 237 238 <SendViaChatDialog 239 control={sendViaChatControl} 240 onSelectChat={onSelectChatToShareTo} 241 /> 242 </> 243 ) 244} 245ShareMenuItems = memo(ShareMenuItems) 246export {ShareMenuItems}