Bluesky app fork with some witchin' additions 馃挮 witchsky.app
bluesky fork client
at main 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}