Bluesky app fork with some witchin' additions 馃挮 witchsky.app
bluesky fork client
119
fork

Configure Feed

Select the types of activity you want to include in your feed.

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