Bluesky app fork with some witchin' additions 馃挮
0
fork

Configure Feed

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

1import {memo, useMemo, useState} from 'react' 2import {type Insets} from 'react-native' 3import { 4 type AppBskyFeedDefs, 5 type AppBskyFeedPost, 6 type AppBskyFeedThreadgate, 7 AtUri, 8 type RichText as RichTextAPI, 9} from '@atproto/api' 10import {msg} from '@lingui/macro' 11import {useLingui} from '@lingui/react' 12 13import {makeProfileLink} from '#/lib/routes/links' 14import {shareUrl} from '#/lib/sharing' 15import {toShareUrl} from '#/lib/strings/url-helpers' 16import {logger} from '#/logger' 17import {type Shadow} from '#/state/cache/post-shadow' 18import {useFeedFeedbackContext} from '#/state/feed-feedback' 19import {EventStopper} from '#/view/com/util/EventStopper' 20import {native} from '#/alf' 21import {ArrowShareRight_Stroke2_Corner2_Rounded as ArrowShareRightIcon} from '#/components/icons/ArrowShareRight' 22import {useMenuControl} from '#/components/Menu' 23import * as Menu from '#/components/Menu' 24import {PostControlButton, PostControlButtonIcon} from '../PostControlButton' 25import {ShareMenuItems} from './ShareMenuItems' 26 27let ShareMenuButton = ({ 28 testID, 29 post, 30 big, 31 record, 32 richText, 33 timestamp, 34 threadgateRecord, 35 onShare, 36 hitSlop, 37 logContext, 38}: { 39 testID: string 40 post: Shadow<AppBskyFeedDefs.PostView> 41 big?: boolean 42 record: AppBskyFeedPost.Record 43 richText: RichTextAPI 44 timestamp: string 45 threadgateRecord?: AppBskyFeedThreadgate.Record 46 onShare: () => void 47 hitSlop?: Insets 48 logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo' 49}): React.ReactNode => { 50 const {_} = useLingui() 51 const {feedDescriptor} = useFeedFeedbackContext() 52 53 const menuControl = useMenuControl() 54 const [hasBeenOpen, setHasBeenOpen] = useState(false) 55 const lazyMenuControl = useMemo( 56 () => ({ 57 ...menuControl, 58 open() { 59 setHasBeenOpen(true) 60 // HACK. We need the state update to be flushed by the time 61 // menuControl.open() fires but RN doesn't expose flushSync. 62 setTimeout(menuControl.open) 63 64 logger.metric( 65 'post:share', 66 { 67 uri: post.uri, 68 authorDid: post.author.did, 69 logContext, 70 feedDescriptor, 71 postContext: big ? 'thread' : 'feed', 72 }, 73 {statsig: true}, 74 ) 75 }, 76 }), 77 [ 78 menuControl, 79 setHasBeenOpen, 80 big, 81 logContext, 82 feedDescriptor, 83 post.uri, 84 post.author.did, 85 ], 86 ) 87 88 const onNativeLongPress = () => { 89 logger.metric('share:press:nativeShare', {}, {statsig: true}) 90 const urip = new AtUri(post.uri) 91 const href = makeProfileLink(post.author, 'post', urip.rkey) 92 const url = toShareUrl(href) 93 shareUrl(url) 94 onShare() 95 } 96 97 return ( 98 <EventStopper onKeyDown={false}> 99 <Menu.Root control={lazyMenuControl}> 100 <Menu.Trigger label={_(msg`Open share menu`)}> 101 {({props}) => { 102 return ( 103 <PostControlButton 104 testID="postShareBtn" 105 big={big} 106 label={props.accessibilityLabel} 107 {...props} 108 onLongPress={native(onNativeLongPress)} 109 hitSlop={hitSlop}> 110 <PostControlButtonIcon icon={ArrowShareRightIcon} /> 111 </PostControlButton> 112 ) 113 }} 114 </Menu.Trigger> 115 {hasBeenOpen && ( 116 // Lazily initialized. Once mounted, they stay mounted. 117 <ShareMenuItems 118 testID={testID} 119 post={post} 120 record={record} 121 richText={richText} 122 timestamp={timestamp} 123 threadgateRecord={threadgateRecord} 124 onShare={onShare} 125 /> 126 )} 127 </Menu.Root> 128 </EventStopper> 129 ) 130} 131 132ShareMenuButton = memo(ShareMenuButton) 133export {ShareMenuButton}