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