forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {useMemo} from 'react'
2import {ScrollView, View} from 'react-native'
3import {AppBskyEmbedVideo, AtUri} from '@atproto/api'
4import {msg} from '@lingui/core/macro'
5import {useLingui} from '@lingui/react'
6import {Trans} from '@lingui/react/macro'
7import {useFocusEffect} from '@react-navigation/native'
8import {useQueryClient} from '@tanstack/react-query'
9
10import {VIDEO_FEED_URI} from '#/lib/constants'
11import {makeCustomFeedLink} from '#/lib/routes/links'
12import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons'
13import {RQKEY, usePostFeedQuery} from '#/state/queries/post-feed'
14import {BlockDrawerGesture} from '#/view/shell/BlockDrawerGesture'
15import {atoms as a, tokens, useGutters, useTheme} from '#/alf'
16import {ButtonIcon} from '#/components/Button'
17import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRight} from '#/components/icons/Chevron'
18import {Link} from '#/components/Link'
19import {Text} from '#/components/Typography'
20import {
21 CompactVideoPostCard,
22 CompactVideoPostCardPlaceholder,
23} from '#/components/VideoPostCard'
24import {useAnalytics} from '#/analytics'
25
26const CARD_WIDTH = 100
27
28const FEED_DESC = `feedgen|${VIDEO_FEED_URI}`
29const FEED_PARAMS: {
30 feedCacheKey: 'explore'
31} = {
32 feedCacheKey: 'explore',
33}
34
35export function ExploreTrendingVideos() {
36 const gutters = useGutters([0, 'base'])
37 const {data, isLoading, error} = usePostFeedQuery(FEED_DESC, FEED_PARAMS)
38
39 // Refetch on tab change if nothing else is using this query.
40 const queryClient = useQueryClient()
41 useFocusEffect(() => {
42 return () => {
43 const query = queryClient
44 .getQueryCache()
45 .find({queryKey: RQKEY(FEED_DESC, FEED_PARAMS)})
46 if (query && query.getObserversCount() <= 1) {
47 query.fetch()
48 }
49 }
50 })
51
52 // const {data: saved} = useSavedFeeds()
53 // const isSavedAlready = useMemo(() => {
54 // return !!saved?.feeds?.some(info => info.config.value === VIDEO_FEED_URI)
55 // }, [saved])
56
57 // const {mutateAsync: addSavedFeeds, isPending: isPinPending} =
58 // useAddSavedFeedsMutation()
59 // const pinFeed = useCallback(
60 // (e: any) => {
61 // e.preventDefault()
62
63 // addSavedFeeds([
64 // {
65 // type: 'feed',
66 // value: VIDEO_FEED_URI,
67 // pinned: true,
68 // },
69 // ])
70
71 // // prevent navigation
72 // return false
73 // },
74 // [addSavedFeeds],
75 // )
76
77 if (error) {
78 return null
79 }
80
81 return (
82 <View style={[a.pb_xl]}>
83 <BlockDrawerGesture>
84 <ScrollView
85 horizontal
86 showsHorizontalScrollIndicator={false}
87 decelerationRate="fast"
88 snapToInterval={CARD_WIDTH + tokens.space.sm}>
89 <View
90 style={[
91 a.pt_lg,
92 a.flex_row,
93 a.gap_sm,
94 {
95 paddingLeft: gutters.paddingLeft,
96 paddingRight: gutters.paddingRight,
97 },
98 ]}>
99 {isLoading ? (
100 Array(10)
101 .fill(0)
102 .map((_, i) => (
103 <View key={i} style={[{width: CARD_WIDTH}]}>
104 <CompactVideoPostCardPlaceholder />
105 </View>
106 ))
107 ) : error || !data ? (
108 <Text>
109 <Trans>Whoops! Trending videos failed to load.</Trans>
110 </Text>
111 ) : (
112 <VideoCards data={data} />
113 )}
114 </View>
115 </ScrollView>
116 </BlockDrawerGesture>
117
118 {/* {!isSavedAlready && (
119 <View
120 style={[
121 gutters,
122 a.pt_lg,
123 a.flex_row,
124 a.align_center,
125 a.justify_between,
126 a.gap_xl,
127 ]}>
128 <Text style={[a.flex_1, a.text_sm, a.leading_snug]}>
129 <Trans>
130 Pin the trending videos feed to your home screen for easy access
131 </Trans>
132 </Text>
133 <Button
134 disabled={isPinPending}
135 label={_(msg`Pin`)}
136 size="small"
137 variant="outline"
138 color="secondary"
139 onPress={pinFeed}>
140 <ButtonText>{_(msg`Pin`)}</ButtonText>
141 <ButtonIcon icon={Pin} position="right" />
142 </Button>
143 </View>
144 )} */}
145 </View>
146 )
147}
148
149function VideoCards({
150 data,
151}: {
152 data: Exclude<ReturnType<typeof usePostFeedQuery>['data'], undefined>
153}) {
154 const t = useTheme()
155 const {_} = useLingui()
156 const ax = useAnalytics()
157 const enableSquareButtons = useEnableSquareButtons()
158 const items = useMemo(() => {
159 return data.pages
160 .flatMap(page => page.slices)
161 .map(slice => slice.items[0])
162 .filter(Boolean)
163 .filter(item => AppBskyEmbedVideo.isView(item.post.embed))
164 .slice(0, 8)
165 }, [data])
166 const href = useMemo(() => {
167 const urip = new AtUri(VIDEO_FEED_URI)
168 return makeCustomFeedLink(urip.host, urip.rkey, undefined, 'explore')
169 }, [])
170
171 return (
172 <>
173 {items.map(item => (
174 <View key={item.post.uri} style={[{width: CARD_WIDTH}]}>
175 <CompactVideoPostCard
176 post={item.post}
177 moderation={item.moderation}
178 sourceContext={{
179 type: 'feedgen',
180 uri: VIDEO_FEED_URI,
181 sourceInterstitial: 'explore',
182 }}
183 onInteract={() => {
184 ax.metric('videoCard:click', {context: 'interstitial:explore'})
185 }}
186 />
187 </View>
188 ))}
189
190 <View style={[{width: CARD_WIDTH * 2}]}>
191 <Link
192 to={href}
193 label={_(msg`View more`)}
194 style={[
195 a.justify_center,
196 a.align_center,
197 a.flex_1,
198 a.rounded_md,
199 t.atoms.bg_contrast_25,
200 ]}>
201 {({pressed}) => (
202 <View
203 style={[
204 a.flex_row,
205 a.align_center,
206 a.gap_md,
207 {
208 opacity: pressed ? 0.6 : 1,
209 },
210 ]}>
211 <Text style={[a.text_md]}>
212 <Trans>View more</Trans>
213 </Text>
214 <View
215 style={[
216 a.align_center,
217 a.justify_center,
218 enableSquareButtons ? a.rounded_sm : a.rounded_full,
219 {
220 width: 34,
221 height: 34,
222 backgroundColor: t.palette.primary_500,
223 },
224 ]}>
225 <ButtonIcon icon={ChevronRight} />
226 </View>
227 </View>
228 )}
229 </Link>
230 </View>
231 </>
232 )
233}