Bluesky app fork with some witchin' additions 💫 witchsky.app
bluesky fork client
at main 234 lines 7.5 kB view raw
1import React from 'react' 2import {View} from 'react-native' 3import {AppBskyGraphDefs} from '@atproto/api' 4import {msg} from '@lingui/core/macro' 5import {useLingui} from '@lingui/react' 6import {Trans} from '@lingui/react/macro' 7import {useQueryClient} from '@tanstack/react-query' 8 9import {useGoBack} from '#/lib/hooks/useGoBack' 10import {sanitizeHandle} from '#/lib/strings/handles' 11import {logger} from '#/logger' 12import { 13 RQKEY_ROOT as listQueryRoot, 14 useListBlockMutation, 15 useListMuteMutation, 16} from '#/state/queries/list' 17import { 18 type UsePreferencesQueryResponse, 19 useRemoveFeedMutation, 20} from '#/state/queries/preferences' 21import {useSession} from '#/state/session' 22import * as Toast from '#/view/com/util/Toast' 23import {CenteredView} from '#/view/com/util/Views' 24import {atoms as a, useBreakpoints, useTheme} from '#/alf' 25import {Button, ButtonIcon, ButtonText} from '#/components/Button' 26import {EyeSlash_Stroke2_Corner0_Rounded as EyeSlash} from '#/components/icons/EyeSlash' 27import {Loader} from '#/components/Loader' 28import {useHider} from '#/components/moderation/Hider' 29import {Text} from '#/components/Typography' 30 31export function ListHiddenScreen({ 32 list, 33 preferences, 34}: { 35 list: AppBskyGraphDefs.ListView 36 preferences: UsePreferencesQueryResponse 37}) { 38 const {_} = useLingui() 39 const t = useTheme() 40 const {currentAccount} = useSession() 41 const {gtMobile} = useBreakpoints() 42 const isOwner = currentAccount?.did === list.creator.did 43 const goBack = useGoBack() 44 const queryClient = useQueryClient() 45 46 const isModList = list.purpose === AppBskyGraphDefs.MODLIST 47 48 const [isProcessing, setIsProcessing] = React.useState(false) 49 const listBlockMutation = useListBlockMutation() 50 const listMuteMutation = useListMuteMutation() 51 const {mutateAsync: removeSavedFeed} = useRemoveFeedMutation() 52 53 const {setIsContentVisible} = useHider() 54 55 const savedFeedConfig = preferences.savedFeeds.find(f => f.value === list.uri) 56 57 const onUnsubscribe = async () => { 58 setIsProcessing(true) 59 if (list.viewer?.muted) { 60 try { 61 await listMuteMutation.mutateAsync({uri: list.uri, mute: false}) 62 } catch (e) { 63 setIsProcessing(false) 64 logger.error('Failed to unmute list', {message: e}) 65 Toast.show( 66 _( 67 msg`There was an issue. Please check your internet connection and try again.`, 68 ), 69 ) 70 return 71 } 72 } 73 if (list.viewer?.blocked) { 74 try { 75 await listBlockMutation.mutateAsync({uri: list.uri, block: false}) 76 } catch (e) { 77 setIsProcessing(false) 78 logger.error('Failed to unblock list', {message: e}) 79 Toast.show( 80 _( 81 msg`There was an issue. Please check your internet connection and try again.`, 82 ), 83 ) 84 return 85 } 86 } 87 queryClient.invalidateQueries({ 88 queryKey: [listQueryRoot], 89 }) 90 Toast.show(_(msg`Unsubscribed from list`)) 91 setIsProcessing(false) 92 } 93 94 const onRemoveList = async () => { 95 if (!savedFeedConfig) return 96 try { 97 await removeSavedFeed(savedFeedConfig) 98 Toast.show(_(msg`Removed from saved feeds`)) 99 } catch (e) { 100 logger.error('Failed to remove list from saved feeds', {message: e}) 101 Toast.show( 102 _( 103 msg`There was an issue. Please check your internet connection and try again.`, 104 ), 105 ) 106 } finally { 107 setIsProcessing(false) 108 } 109 } 110 111 return ( 112 <CenteredView 113 style={[ 114 a.flex_1, 115 a.align_center, 116 a.gap_5xl, 117 !gtMobile && a.justify_between, 118 t.atoms.border_contrast_low, 119 {paddingTop: 175, paddingBottom: 110}, 120 ]} 121 sideBorders={true}> 122 <View style={[a.w_full, a.align_center, a.gap_lg]}> 123 <EyeSlash 124 style={{color: t.atoms.text_contrast_medium.color}} 125 height={42} 126 width={42} 127 /> 128 <View style={[a.gap_sm, a.align_center]}> 129 <Text style={[a.font_semi_bold, a.text_3xl]}> 130 {list.creator.viewer?.blocking || list.creator.viewer?.blockedBy ? ( 131 <Trans>Creator has been blocked</Trans> 132 ) : ( 133 <Trans>List has been hidden</Trans> 134 )} 135 </Text> 136 <Text 137 style={[ 138 a.text_md, 139 a.text_center, 140 a.px_md, 141 t.atoms.text_contrast_high, 142 {lineHeight: 1.4}, 143 ]}> 144 {list.creator.viewer?.blocking || list.creator.viewer?.blockedBy ? ( 145 <Trans> 146 Either the creator of this list has blocked you or you have 147 blocked the creator. 148 </Trans> 149 ) : isOwner ? ( 150 <Trans> 151 This list created by you contains possible violations of 152 Bluesky's community guidelines in its name or description. 153 </Trans> 154 ) : ( 155 <Trans> 156 This list – created by{' '} 157 <Text style={[a.font_semi_bold]}> 158 {sanitizeHandle(list.creator.handle, '@')} 159 </Text>{' '} 160 – contains possible violations of Bluesky's community guidelines 161 in its name or description. 162 </Trans> 163 )} 164 </Text> 165 </View> 166 </View> 167 <View style={[a.gap_md, gtMobile ? {width: 350} : [a.w_full, a.px_lg]]}> 168 <View style={[a.gap_md]}> 169 {savedFeedConfig ? ( 170 <Button 171 variant="solid" 172 color="secondary" 173 size="large" 174 label={_(msg`Remove from saved feeds`)} 175 onPress={onRemoveList} 176 disabled={isProcessing}> 177 <ButtonText> 178 <Trans>Remove from saved feeds</Trans> 179 </ButtonText> 180 {isProcessing ? ( 181 <ButtonIcon icon={Loader} position="right" /> 182 ) : null} 183 </Button> 184 ) : null} 185 {isOwner ? ( 186 <Button 187 variant="solid" 188 color="secondary" 189 size="large" 190 label={_(msg`Show list anyway`)} 191 onPress={() => setIsContentVisible(true)} 192 disabled={isProcessing}> 193 <ButtonText> 194 <Trans>Show anyway</Trans> 195 </ButtonText> 196 </Button> 197 ) : list.viewer?.muted || list.viewer?.blocked ? ( 198 <Button 199 variant="solid" 200 color="secondary" 201 size="large" 202 label={_(msg`Unsubscribe from list`)} 203 onPress={() => { 204 if (isModList) { 205 onUnsubscribe() 206 } else { 207 onRemoveList() 208 } 209 }} 210 disabled={isProcessing}> 211 <ButtonText> 212 <Trans>Unsubscribe from list</Trans> 213 </ButtonText> 214 {isProcessing ? ( 215 <ButtonIcon icon={Loader} position="right" /> 216 ) : null} 217 </Button> 218 ) : null} 219 </View> 220 <Button 221 variant="solid" 222 color="primary" 223 label={_(msg`Return to previous page`)} 224 onPress={goBack} 225 size="large" 226 disabled={isProcessing}> 227 <ButtonText> 228 <Trans>Go Back</Trans> 229 </ButtonText> 230 </Button> 231 </View> 232 </CenteredView> 233 ) 234}