diff options
author | Hailey <me@haileyok.com> | 2025-01-19 17:17:41 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-19 17:17:41 -0800 |
commit | 34582edf3ea17789684100172d6dd496220482b0 (patch) | |
tree | ca29a927bf015107a60a867d8266274c8a78de49 /src/view/com/posts/PostFeed.tsx | |
parent | cb020655504dd0d39f8e91fd517f14dc4a82c307 (diff) | |
download | voidsky-34582edf3ea17789684100172d6dd496220482b0.tar.zst |
yolo (#7499)
* tweaks to constants (#7478) * add did * use correct did * typo * tweak * Prevent Drawer gesture conflicting with Suggestions scroll (#7468) * Extract BlockDrawerGeesture * Block drawer when scrolling interstitials (cherry picked from commit 9e3f2f43745eed9c71cb985e48135b7363d91aa9) * yolo interstitial * yolo mode * right swipe * fix nav gesture * vibe controls * collapsible post text * rm blurview, cover for tall videos * smarter video source handling * use thumbnails, improve perf significantly * better android loading * improve aspect ratio * optimize source changes * rm spinner on ios * whoops, remove debug `false` * FIX WRONG VIDEOS SHOWING UP * don't spring on way down * release video players when leaving screen * remove jank animation * Add grid * improve contract, fix double tap * Filter out posts without videos * Only do grid on native * Pipe through feedSourceUri and link to feed * Handle passed through params * Partial revert, just filter posts to start at index * Clean up cards, remove entry interstitial * Tweak handle * Change constant name * Rename some things * Make types legit * Clean up more naming * Add placeholder for grid view * Handle web, set up new organization * Begin work on Header * Replace types * Squashed commit of the following: commit 3d1be4c0f19789dd3c5a3572ec1acd744a2edb80 Author: Samuel Newman <mozzius@protonmail.com> Date: Fri Jan 17 01:08:05 2025 +0000 extend animation commit c9f199413b018efcbd9d8d2a58dd05eb41e7acb7 Author: Samuel Newman <mozzius@protonmail.com> Date: Fri Jan 17 01:01:24 2025 +0000 fix gap commit 22e520795f50efda176f21a5e967cb27d0cdd907 Author: Samuel Newman <mozzius@protonmail.com> Date: Fri Jan 17 00:50:16 2025 +0000 thinner bar, format time commit c32427f21405294ed3567545629a2964c4af59fe Author: Samuel Newman <mozzius@protonmail.com> Date: Fri Jan 17 00:47:57 2025 +0000 fix 2 in 3 screens commit cbf84c08d64ca0a08ba9070ef5db918f89aa4296 Author: Samuel Newman <mozzius@protonmail.com> Date: Fri Jan 17 00:45:46 2025 +0000 rm unneeded var commit 7e0e100177bb1cd0e64c0841bb7685c7f1eb857f Author: Samuel Newman <mozzius@protonmail.com> Date: Fri Jan 17 00:41:18 2025 +0000 scrubberrrrr * use white with opacity rather than gray * Simultaneous gesture * cleanup attempt * fix jank * link to profile on press * fix jitter fr this time * mostly fix android flicker * Maybe fix row generation * Add content hider to video card * emoji in post text * reduce update rate * fix type error * Fix grid layout trailing single item * Add Discover interstitial, settings, includes pin for now * Explore interstitial, handle dimissal, pinning, compact card * Only use grid placeholder on native * Update events * Add feature gate * android nav bar fixes + lower update speed * fix interval + decel rate on interstitials * attempt to fix broken scrub on android (not working) * follow button * Part out the interstitials for perf, add view more * Remove prod web route * Wrap interstitials with BlockDrawerGesture * Bring video cropping in line with images (#7462) * Mimic image cropping for videos on web * Same on native * Rename variables for clarity * Fix Android scrubbing * Add FeedFeedbackProvider * Remove swipe gesture * fix light status bar behaviour * bump * feedback * Copy pasta to new location * Copy pasta part deux * Filter only videos * Make whole text clickable to expand (cherry picked from commit 4cf31120779f4e06eb4c296b3d4b53814d432b07) * move scrubber to own file * end card * add icon to end card * add min view time to viewability config * play haptic on like * tweak feedback * tweak feedback again * Moderation (cherry picked from commit 6b6b471cfb363031284b3e7a1f6e0ade3ac4ae47) * remove bad check * fix feedback for new video grid * change prop name to items as well * Simplify logic * Fix mod footer * Give scrubber more space on android * Add subtle track behind scrubber, adjust opacity * wire in feed context again... * Add better a11y desc to card * Fix key issue * Update a11y copy * Fix scrubber height * improve scrubber animation * Make follow button more obvious * Make header back button more clear * Disable interactions with actual video el * keep content away from the bottom safe area * fix blur * fix moderation issue * improve contrast on mod screen * Make moderation static per item * Memoize rows * Optimizations * Take video moderation into account * Only blur titles for list blur * Change copy * Bump blur radius * animate text in both directions * Rm unused field * Filter by root early * Refactor for clarity * add compose prompt to scrubber * rm log * tweak gradient * Bump SDK, use contentMode to power video feed * Ensure ProfileFeed view also supports video feed * improve scrubber on android * rm border from footer * Update prod video feed did * Separate caches * Add lil hover to View More * Fix undefined logic, remove header for interstitial * Ungate * Fix stuckness * remove extra useless map * Fix effect cleanup * Send seen without cleanup * Simplify react stuff * Earlier early return to avoid loading flash * remove scrubber placeholder * Remove opacity hack * Render useEvent conditionally * Fix Android flash --------- Co-authored-by: dan <dan.abramov@gmail.com> Co-authored-by: Samuel Newman <mozzius@protonmail.com> Co-authored-by: Eric Bailey <git@esb.lol>
Diffstat (limited to 'src/view/com/posts/PostFeed.tsx')
-rw-r--r-- | src/view/com/posts/PostFeed.tsx | 271 |
1 files changed, 196 insertions, 75 deletions
diff --git a/src/view/com/posts/PostFeed.tsx b/src/view/com/posts/PostFeed.tsx index f9b2e6e76..554415faf 100644 --- a/src/view/com/posts/PostFeed.tsx +++ b/src/view/com/posts/PostFeed.tsx @@ -9,7 +9,7 @@ import { View, ViewStyle, } from 'react-native' -import {AppBskyActorDefs} from '@atproto/api' +import {AppBskyActorDefs, AppBskyEmbedVideo} from '@atproto/api' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useQueryClient} from '@tanstack/react-query' @@ -20,7 +20,7 @@ import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' import {logEvent} from '#/lib/statsig/statsig' import {useTheme} from '#/lib/ThemeContext' import {logger} from '#/logger' -import {isIOS, isWeb} from '#/platform/detection' +import {isIOS, isNative, isWeb} from '#/platform/detection' import {listenPostCreated} from '#/state/events' import {useFeedFeedbackContext} from '#/state/feed-feedback' import {useTrendingSettings} from '#/state/preferences/trending' @@ -29,18 +29,24 @@ import { FeedDescriptor, FeedParams, FeedPostSlice, + FeedPostSliceItem, pollLatest, RQKEY, usePostFeedQuery, } from '#/state/queries/post-feed' import {useSession} from '#/state/session' import {useProgressGuide} from '#/state/shell/progress-guide' +import {List, ListRef} from '#/view/com/util/List' +import {PostFeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' +import {LoadMoreRetryBtn} from '#/view/com/util/LoadMoreRetryBtn' import {useBreakpoints} from '#/alf' import {ProgressGuide, SuggestedFollows} from '#/components/FeedInterstitials' +import { + PostFeedVideoGridRow, + PostFeedVideoGridRowPlaceholder, +} from '#/components/feeds/PostFeedVideoGridRow' import {TrendingInterstitial} from '#/components/interstitials/Trending' -import {List, ListRef} from '../util/List' -import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder' -import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' +import {TrendingVideos as TrendingVideosInterstitial} from '#/components/interstitials/TrendingVideos' import {DiscoverFallbackHeader} from './DiscoverFallbackHeader' import {FeedShutdownMsg} from './FeedShutdownMsg' import {PostFeedErrorMessage} from './PostFeedErrorMessage' @@ -69,7 +75,7 @@ type FeedRow = key: string } | { - type: 'slice' + type: 'slice' // TODO can we remove? key: string slice: FeedPostSlice } @@ -81,6 +87,17 @@ type FeedRow = showReplyTo: boolean } | { + type: 'videoGridRowPlaceholder' + key: string + } + | { + type: 'videoGridRow' + key: string + items: FeedPostSliceItem[] + sourceFeedUri: string + feedContexts: (string | undefined)[] + } + | { type: 'sliceViewFullThread' key: string uri: string @@ -97,12 +114,28 @@ type FeedRow = type: 'interstitialTrending' key: string } + | { + type: 'interstitialTrendingVideos' + key: string + } -export function getFeedPostSlice(feedRow: FeedRow): FeedPostSlice | null { +export function getItemsForFeedback(feedRow: FeedRow): + | { + item: FeedPostSliceItem + feedContext: string | undefined + }[] { if (feedRow.type === 'sliceItem') { - return feedRow.slice + return feedRow.slice.items.map(item => ({ + item, + feedContext: feedRow.slice.feedContext, + })) + } else if (feedRow.type === 'videoGridRow') { + return feedRow.items.map((item, i) => ({ + item, + feedContext: feedRow.feedContexts[i], + })) } else { - return null + return [] } } @@ -131,6 +164,7 @@ let PostFeed = ({ extraData, savedFeedConfig, initialNumToRender: initialNumToRenderOverride, + isVideoFeed = false, }: { feed: FeedDescriptor feedParams?: FeedParams @@ -152,6 +186,7 @@ let PostFeed = ({ extraData?: any savedFeedConfig?: AppBskyActorDefs.SavedFeed initialNumToRender?: number + isVideoFeed?: boolean }): React.ReactNode => { const theme = useTheme() const {_} = useLingui() @@ -163,8 +198,10 @@ let PostFeed = ({ const checkForNewRef = React.useRef<(() => void) | null>(null) const lastFetchRef = React.useRef<number>(Date.now()) const [feedType, feedUri, feedTab] = feed.split('|') - const {gtTablet} = useBreakpoints() + const {gtMobile, gtTablet} = useBreakpoints() + const areVideoFeedsEnabled = isNative + const feedCacheKey = feedParams?.feedCacheKey const opts = React.useMemo( () => ({enabled, ignoreFilterFor}), [enabled, ignoreFilterFor], @@ -267,10 +304,10 @@ let PostFeed = ({ const showProgressIntersitial = (followProgressGuide || followAndLikeProgressGuide) && !isDesktop - const {trendingDisabled} = useTrendingSettings() + const {trendingDisabled, trendingVideoDisabled} = useTrendingSettings() const feedItems: FeedRow[] = React.useMemo(() => { - let feedKind: 'following' | 'discover' | 'profile' | undefined + let feedKind: 'following' | 'discover' | 'profile' | 'thevids' | undefined if (feedType === 'following') { feedKind = 'following' } else if (feedUri === DISCOVER_FEED_URI) { @@ -303,81 +340,132 @@ let PostFeed = ({ }) } else if (data) { let sliceIndex = -1 - for (const page of data?.pages) { - for (const slice of page.slices) { + + if (isVideoFeed) { + const videos: { + item: FeedPostSliceItem + feedContext: string | undefined + }[] = [] + for (const page of data.pages) { + for (const slice of page.slices) { + const item = slice.items.at(0) + if (item && AppBskyEmbedVideo.isView(item.post.embed)) { + videos.push({item, feedContext: slice.feedContext}) + } + } + } + + const rows: { + item: FeedPostSliceItem + feedContext: string | undefined + }[][] = [] + for (let i = 0; i < videos.length; i++) { + const video = videos[i] + const item = video.item + const cols = gtMobile ? 3 : 2 + const rowItem = {item, feedContext: video.feedContext} + if (i % cols === 0) { + rows.push([rowItem]) + } else { + rows[rows.length - 1].push(rowItem) + } + } + + for (const row of rows) { sliceIndex++ + arr.push({ + type: 'videoGridRow', + key: row.map(r => r.item._reactKey).join('-'), + items: row.map(r => r.item), + sourceFeedUri: feedUri, + feedContexts: row.map(r => r.feedContext), + }) + } + } else { + for (const page of data?.pages) { + for (const slice of page.slices) { + sliceIndex++ - if (hasSession) { - if (feedKind === 'discover') { - if (sliceIndex === 0) { - if (showProgressIntersitial) { + if (hasSession) { + if (feedKind === 'discover') { + if (sliceIndex === 0) { + if (showProgressIntersitial) { + arr.push({ + type: 'interstitialProgressGuide', + key: 'interstitial-' + sliceIndex + '-' + lastFetchedAt, + }) + } + if (!gtTablet && !trendingDisabled) { + arr.push({ + type: 'interstitialTrending', + key: + 'interstitial2-' + sliceIndex + '-' + lastFetchedAt, + }) + } + } else if (sliceIndex === 15) { + if (areVideoFeedsEnabled && !trendingVideoDisabled) { + arr.push({ + type: 'interstitialTrendingVideos', + key: 'interstitial-' + sliceIndex + '-' + lastFetchedAt, + }) + } + } else if (sliceIndex === 30) { arr.push({ - type: 'interstitialProgressGuide', + type: 'interstitialFollows', key: 'interstitial-' + sliceIndex + '-' + lastFetchedAt, }) } - if (!gtTablet && !trendingDisabled) { + } else if (feedKind === 'profile') { + if (sliceIndex === 5) { arr.push({ - type: 'interstitialTrending', - key: 'interstitial2-' + sliceIndex + '-' + lastFetchedAt, + type: 'interstitialFollows', + key: 'interstitial-' + sliceIndex + '-' + lastFetchedAt, }) } - } else if (sliceIndex === 30) { - arr.push({ - type: 'interstitialFollows', - key: 'interstitial-' + sliceIndex + '-' + lastFetchedAt, - }) - } - } else if (feedKind === 'profile') { - if (sliceIndex === 5) { - arr.push({ - type: 'interstitialFollows', - key: 'interstitial-' + sliceIndex + '-' + lastFetchedAt, - }) } } - } - if (slice.isIncompleteThread && slice.items.length >= 3) { - const beforeLast = slice.items.length - 2 - const last = slice.items.length - 1 - arr.push({ - type: 'sliceItem', - key: slice.items[0]._reactKey, - slice: slice, - indexInSlice: 0, - showReplyTo: false, - }) - arr.push({ - type: 'sliceViewFullThread', - key: slice._reactKey + '-viewFullThread', - uri: slice.items[0].uri, - }) - arr.push({ - type: 'sliceItem', - key: slice.items[beforeLast]._reactKey, - slice: slice, - indexInSlice: beforeLast, - showReplyTo: - slice.items[beforeLast].parentAuthor?.did !== - slice.items[beforeLast].post.author.did, - }) - arr.push({ - type: 'sliceItem', - key: slice.items[last]._reactKey, - slice: slice, - indexInSlice: last, - showReplyTo: false, - }) - } else { - for (let i = 0; i < slice.items.length; i++) { + if (slice.isIncompleteThread && slice.items.length >= 3) { + const beforeLast = slice.items.length - 2 + const last = slice.items.length - 1 + arr.push({ + type: 'sliceItem', + key: slice.items[0]._reactKey, + slice: slice, + indexInSlice: 0, + showReplyTo: false, + }) + arr.push({ + type: 'sliceViewFullThread', + key: slice._reactKey + '-viewFullThread', + uri: slice.items[0].uri, + }) arr.push({ type: 'sliceItem', - key: slice.items[i]._reactKey, + key: slice.items[beforeLast]._reactKey, slice: slice, - indexInSlice: i, - showReplyTo: i === 0, + indexInSlice: beforeLast, + showReplyTo: + slice.items[beforeLast].parentAuthor?.did !== + slice.items[beforeLast].post.author.did, }) + arr.push({ + type: 'sliceItem', + key: slice.items[last]._reactKey, + slice: slice, + indexInSlice: last, + showReplyTo: false, + }) + } else { + for (let i = 0; i < slice.items.length; i++) { + arr.push({ + type: 'sliceItem', + key: slice.items[i]._reactKey, + slice: slice, + indexInSlice: i, + showReplyTo: i === 0, + }) + } } } } @@ -390,10 +478,17 @@ let PostFeed = ({ }) } } else { - arr.push({ - type: 'loading', - key: 'loading', - }) + if (isVideoFeed) { + arr.push({ + type: 'videoGridRowPlaceholder', + key: 'videoGridRowPlaceholder', + }) + } else { + arr.push({ + type: 'loading', + key: 'loading', + }) + } } return arr @@ -409,7 +504,11 @@ let PostFeed = ({ hasSession, showProgressIntersitial, trendingDisabled, + trendingVideoDisabled, gtTablet, + gtMobile, + isVideoFeed, + areVideoFeedsEnabled, ]) // events @@ -498,6 +597,8 @@ let PostFeed = ({ return <ProgressGuide /> } else if (row.type === 'interstitialTrending') { return <TrendingInterstitial /> + } else if (row.type === 'interstitialTrendingVideos') { + return <TrendingVideosInterstitial /> } else if (row.type === 'sliceItem') { const slice = row.slice if (slice.isFallbackMarker) { @@ -532,6 +633,25 @@ let PostFeed = ({ ) } else if (row.type === 'sliceViewFullThread') { return <ViewFullThread uri={row.uri} /> + } else if (row.type === 'videoGridRowPlaceholder') { + return ( + <View> + <PostFeedVideoGridRowPlaceholder /> + <PostFeedVideoGridRowPlaceholder /> + <PostFeedVideoGridRowPlaceholder /> + </View> + ) + } else if (row.type === 'videoGridRow') { + return ( + <PostFeedVideoGridRow + items={row.items} + sourceContext={{ + type: 'feedgen', + uri: row.sourceFeedUri, + sourceInterstitial: feedCacheKey ?? 'none', + }} + /> + ) } else { return null } @@ -545,6 +665,7 @@ let PostFeed = ({ _, onPressRetryLoadMore, feedUri, + feedCacheKey, ], ) |