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