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

Configure Feed

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

at fbd1138d97dda2df66bee13ad3ca6e83d55ebc25 224 lines 6.6 kB view raw
1import {type StyleProp, View, type ViewStyle} from 'react-native' 2import {AtUri} from '@atproto/api' 3import {msg, Trans} from '@lingui/macro' 4import {useLingui} from '@lingui/react' 5 6import {cleanError} from '#/lib/strings/errors' 7import {isNative, isWeb} from '#/platform/detection' 8import {useModerationOpts} from '#/state/preferences/moderation-opts' 9import {getFeedTypeFromUri} from '#/state/queries/feed' 10import {useProfileQuery} from '#/state/queries/profile' 11import {atoms as a, useTheme, web} from '#/alf' 12import {Button, ButtonText} from '#/components/Button' 13import * as Dialog from '#/components/Dialog' 14import {Divider} from '#/components/Divider' 15import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' 16import * as ProfileCard from '#/components/ProfileCard' 17import {Text} from '#/components/Typography' 18 19export function MissingFeed({ 20 style, 21 hideTopBorder, 22 uri, 23 error, 24}: { 25 style?: StyleProp<ViewStyle> 26 hideTopBorder?: boolean 27 uri: string 28 error?: unknown 29}) { 30 const t = useTheme() 31 const {_} = useLingui() 32 const control = Dialog.useDialogControl() 33 34 const type = getFeedTypeFromUri(uri) 35 36 return ( 37 <> 38 <Button 39 label={ 40 type === 'feed' 41 ? _(msg`Could not connect to custom feed`) 42 : _(msg`Deleted list`) 43 } 44 accessibilityHint={_(msg`Tap for more information`)} 45 onPress={control.open} 46 style={[ 47 a.flex_1, 48 a.p_lg, 49 a.gap_md, 50 !hideTopBorder && !a.border_t, 51 t.atoms.border_contrast_low, 52 a.justify_start, 53 style, 54 ]}> 55 <View style={[a.flex_row, a.align_center]}> 56 <View 57 style={[ 58 {width: 36, height: 36}, 59 t.atoms.bg_contrast_25, 60 a.rounded_sm, 61 a.mr_md, 62 a.align_center, 63 a.justify_center, 64 ]}> 65 <WarningIcon size="lg" /> 66 </View> 67 <View style={[a.flex_1]}> 68 <Text 69 emoji 70 style={[a.text_sm, a.font_semi_bold, a.leading_snug, a.italic]} 71 numberOfLines={1}> 72 {type === 'feed' ? ( 73 <Trans>Feed unavailable</Trans> 74 ) : ( 75 <Trans>Deleted list</Trans> 76 )} 77 </Text> 78 <Text 79 style={[ 80 a.text_sm, 81 t.atoms.text_contrast_medium, 82 a.leading_snug, 83 a.italic, 84 ]} 85 numberOfLines={1}> 86 {isWeb ? ( 87 <Trans>Click for information</Trans> 88 ) : ( 89 <Trans>Tap for information</Trans> 90 )} 91 </Text> 92 </View> 93 </View> 94 </Button> 95 96 <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}> 97 <Dialog.Handle /> 98 <DialogInner uri={uri} type={type} error={error} /> 99 </Dialog.Outer> 100 </> 101 ) 102} 103 104function DialogInner({ 105 uri, 106 type, 107 error, 108}: { 109 uri: string 110 type: 'feed' | 'list' 111 error: unknown 112}) { 113 const control = Dialog.useDialogContext() 114 const t = useTheme() 115 const {_} = useLingui() 116 const atUri = new AtUri(uri) 117 const {data: profile, isError: isProfileError} = useProfileQuery({ 118 did: atUri.host, 119 }) 120 const moderationOpts = useModerationOpts() 121 122 return ( 123 <Dialog.ScrollableInner 124 label={ 125 type === 'feed' 126 ? _(msg`Unavailable feed information`) 127 : _(msg`Deleted list`) 128 } 129 style={web({maxWidth: 500})}> 130 <View style={[a.gap_sm]}> 131 <Text style={[a.font_bold, a.text_2xl]}> 132 {type === 'feed' ? ( 133 <Trans>Could not connect to feed service</Trans> 134 ) : ( 135 <Trans>Deleted list</Trans> 136 )} 137 </Text> 138 <Text style={[t.atoms.text_contrast_high, a.leading_snug]}> 139 {type === 'feed' ? ( 140 <Trans> 141 We could not connect to the service that provides this custom 142 feed. It may be temporarily unavailable and experiencing issues, 143 or permanently unavailable. 144 </Trans> 145 ) : ( 146 <Trans>We could not find this list. It was probably deleted.</Trans> 147 )} 148 </Text> 149 <Divider style={[a.my_md]} /> 150 <Text style={[a.font_semi_bold, t.atoms.text_contrast_high]}> 151 {type === 'feed' ? ( 152 <Trans>Feed creator</Trans> 153 ) : ( 154 <Trans>List creator</Trans> 155 )} 156 </Text> 157 {profile && moderationOpts && ( 158 <View style={[a.w_full, a.align_start]}> 159 <ProfileCard.Link profile={profile} onPress={() => control.close()}> 160 <ProfileCard.Header> 161 <ProfileCard.Avatar 162 profile={profile} 163 moderationOpts={moderationOpts} 164 disabledPreview 165 /> 166 <ProfileCard.NameAndHandle 167 profile={profile} 168 moderationOpts={moderationOpts} 169 /> 170 </ProfileCard.Header> 171 </ProfileCard.Link> 172 </View> 173 )} 174 {isProfileError && ( 175 <Text 176 style={[ 177 t.atoms.text_contrast_high, 178 a.italic, 179 a.text_center, 180 a.w_full, 181 ]}> 182 <Trans>Could not find profile</Trans> 183 </Text> 184 )} 185 {type === 'feed' && ( 186 <> 187 <Text 188 style={[a.font_semi_bold, t.atoms.text_contrast_high, a.mt_md]}> 189 <Trans>Feed identifier</Trans> 190 </Text> 191 <Text style={[a.text_md, t.atoms.text_contrast_high, a.italic]}> 192 {atUri.rkey} 193 </Text> 194 </> 195 )} 196 {error instanceof Error && ( 197 <> 198 <Text 199 style={[a.font_semi_bold, t.atoms.text_contrast_high, a.mt_md]}> 200 <Trans>Error message</Trans> 201 </Text> 202 <Text style={[a.text_md, t.atoms.text_contrast_high, a.italic]}> 203 {cleanError(error.message)} 204 </Text> 205 </> 206 )} 207 </View> 208 {isNative && ( 209 <Button 210 label={_(msg`Close`)} 211 onPress={() => control.close()} 212 size="small" 213 variant="solid" 214 color="secondary" 215 style={[a.mt_5xl]}> 216 <ButtonText> 217 <Trans>Close</Trans> 218 </ButtonText> 219 </Button> 220 )} 221 <Dialog.Close /> 222 </Dialog.ScrollableInner> 223 ) 224}