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

Configure Feed

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

at a876aae44ea07494ebea9727350aa060b81f317b 218 lines 6.4 kB view raw
1import {memo, useCallback} from 'react' 2import {View} from 'react-native' 3import {msg, plural} from '@lingui/core/macro' 4import {useLingui} from '@lingui/react' 5import {Trans} from '@lingui/react/macro' 6 7import {useHaptics} from '#/lib/haptics' 8import {useRequireAuth} from '#/state/session' 9import {atoms as a, useTheme} from '#/alf' 10import {Button, ButtonText} from '#/components/Button' 11import * as Dialog from '#/components/Dialog' 12import {CloseQuote_Stroke2_Corner1_Rounded as QuoteIcon} from '#/components/icons/Quote' 13import {Repost_Stroke2_Corner3_Rounded as RepostIcon} from '#/components/icons/Repost' 14import {useFormatPostStatCount} from '#/components/PostControls/util' 15import {Text} from '#/components/Typography' 16import { 17 PostControlButton, 18 PostControlButtonIcon, 19 PostControlButtonText, 20} from './PostControlButton' 21 22interface Props { 23 isReposted: boolean 24 repostCount?: number 25 onRepost: () => void 26 onQuote: () => void 27 big?: boolean 28 embeddingDisabled: boolean 29} 30 31let RepostButton = ({ 32 isReposted, 33 repostCount, 34 onRepost, 35 onQuote, 36 big, 37 embeddingDisabled, 38}: Props): React.ReactNode => { 39 const t = useTheme() 40 const {_} = useLingui() 41 const requireAuth = useRequireAuth() 42 const dialogControl = Dialog.useDialogControl() 43 const formatPostStatCount = useFormatPostStatCount() 44 45 const onPress = () => requireAuth(() => dialogControl.open()) 46 47 const onLongPress = () => 48 requireAuth(() => { 49 if (embeddingDisabled) { 50 dialogControl.open() 51 } else { 52 onQuote() 53 } 54 }) 55 56 return ( 57 <> 58 <PostControlButton 59 testID="repostBtn" 60 active={isReposted} 61 activeColor={t.palette.positive_500} 62 big={big} 63 onPress={onPress} 64 onLongPress={onLongPress} 65 label={ 66 isReposted 67 ? _( 68 msg({ 69 message: `Undo repost (${plural(repostCount || 0, { 70 one: '# repost', 71 other: '# reposts', 72 })})`, 73 comment: 74 'Accessibility label for the repost button when the post has been reposted, verb followed by number of reposts and noun', 75 }), 76 ) 77 : _( 78 msg({ 79 message: `Repost (${plural(repostCount || 0, { 80 one: '# repost', 81 other: '# reposts', 82 })})`, 83 comment: 84 'Accessibility label for the repost button when the post has not been reposted, verb form followed by number of reposts and noun form', 85 }), 86 ) 87 }> 88 <PostControlButtonIcon icon={RepostIcon} /> 89 {typeof repostCount !== 'undefined' && repostCount > 0 && ( 90 <PostControlButtonText testID="repostCount"> 91 {formatPostStatCount(repostCount)} 92 </PostControlButtonText> 93 )} 94 </PostControlButton> 95 <Dialog.Outer 96 control={dialogControl} 97 nativeOptions={{preventExpansion: true}}> 98 <Dialog.Handle /> 99 <RepostButtonDialogInner 100 isReposted={isReposted} 101 onRepost={onRepost} 102 onQuote={onQuote} 103 embeddingDisabled={embeddingDisabled} 104 /> 105 </Dialog.Outer> 106 </> 107 ) 108} 109RepostButton = memo(RepostButton) 110export {RepostButton} 111 112let RepostButtonDialogInner = ({ 113 isReposted, 114 onRepost, 115 onQuote, 116 embeddingDisabled, 117}: { 118 isReposted: boolean 119 onRepost: () => void 120 onQuote: () => void 121 embeddingDisabled: boolean 122}): React.ReactNode => { 123 const t = useTheme() 124 const {_} = useLingui() 125 const playHaptic = useHaptics() 126 const control = Dialog.useDialogContext() 127 128 const onPressRepost = useCallback(() => { 129 if (!isReposted) playHaptic() 130 131 control.close(() => { 132 onRepost() 133 }) 134 }, [control, isReposted, onRepost, playHaptic]) 135 136 const onPressQuote = useCallback(() => { 137 playHaptic() 138 control.close(() => { 139 onQuote() 140 }) 141 }, [control, onQuote, playHaptic]) 142 143 const onPressClose = useCallback(() => control.close(), [control]) 144 145 return ( 146 <Dialog.ScrollableInner label={_(msg`Repost or quote post`)}> 147 <View style={a.gap_xl}> 148 <View style={a.gap_xs}> 149 <Button 150 style={[a.justify_start, a.px_md, a.gap_sm]} 151 label={ 152 isReposted 153 ? _(msg`Remove repost`) 154 : _(msg({message: `Repost`, context: 'action'})) 155 } 156 onPress={onPressRepost} 157 size="large" 158 variant="ghost" 159 color="primary"> 160 <RepostIcon size="lg" fill={t.palette.primary_500} /> 161 <Text style={[a.font_semi_bold, a.text_xl]}> 162 {isReposted ? ( 163 <Trans>Remove repost</Trans> 164 ) : ( 165 <Trans context="action">Repost</Trans> 166 )} 167 </Text> 168 </Button> 169 <Button 170 disabled={embeddingDisabled} 171 testID="quoteBtn" 172 style={[a.justify_start, a.px_md, a.gap_sm]} 173 label={ 174 embeddingDisabled 175 ? _(msg`Quote posts disabled`) 176 : _(msg`Quote post`) 177 } 178 onPress={onPressQuote} 179 size="large" 180 variant="ghost" 181 color="primary"> 182 <QuoteIcon 183 size="lg" 184 fill={ 185 embeddingDisabled 186 ? t.atoms.text_contrast_low.color 187 : t.palette.primary_500 188 } 189 /> 190 <Text 191 style={[ 192 a.font_semi_bold, 193 a.text_xl, 194 embeddingDisabled && t.atoms.text_contrast_low, 195 ]}> 196 {embeddingDisabled ? ( 197 <Trans>Quote posts disabled</Trans> 198 ) : ( 199 <Trans>Quote post</Trans> 200 )} 201 </Text> 202 </Button> 203 </View> 204 <Button 205 label={_(msg`Cancel quote post`)} 206 onPress={onPressClose} 207 size="large" 208 color="secondary"> 209 <ButtonText> 210 <Trans>Cancel</Trans> 211 </ButtonText> 212 </Button> 213 </View> 214 </Dialog.ScrollableInner> 215 ) 216} 217RepostButtonDialogInner = memo(RepostButtonDialogInner) 218export {RepostButtonDialogInner}