Implement FeedFeedback API (#3498)

* Implement onViewableItemsChanged on List.web.tsx

* Introduce onItemSeen to List API

* Add FeedFeedback tracker

* Add clickthrough interaction tracking

* Add engagement interaction tracking

* Reduce duplicate sends, introduce a flushAndReset to be triggered on refreshes, and modify the api design a bit

* Wire up SDK types and feedContext

* Avoid needless function allocations

* Fix schema usage

* Add show more / show less buttons

* Fix minor rendering issue on mobile menu

* Wire up sendInteractions()

* Fix logic error

* Fix: it's item not uri

* Update 'seen' to mean 3 seconds on-screen with some significant portion visible

* Fix non-reactive debounce

* Move methods out

* Use a WeakSet for deduping

* Reset timeout

* 3 -> 2 seconds

* Oopsie

* Throttle instead

* Fix divider

* Remove explicit flush calls

* Rm unused

---------

Co-authored-by: dan <dan.abramov@gmail.com>
This commit is contained in:
Paul Frazee 2024-05-06 19:08:33 -07:00 committed by GitHub
parent e264dfbb87
commit 4fad18b2fa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 516 additions and 64 deletions

View file

@ -19,10 +19,12 @@ import {Text} from '../text/Text'
export const ExternalLinkEmbed = ({
link,
onOpen,
style,
hideAlt,
}: {
link: AppBskyEmbedExternal.ViewExternal
onOpen?: () => void
style?: StyleProp<ViewStyle>
hideAlt?: boolean
}) => {
@ -44,7 +46,7 @@ export const ExternalLinkEmbed = ({
return (
<View style={[a.flex_col, a.rounded_sm, a.overflow_hidden, a.mt_sm]}>
<LinkWrapper link={link} style={style}>
<LinkWrapper link={link} onOpen={onOpen} style={style}>
{link.thumb && !embedPlayerParams ? (
<Image
style={{
@ -97,10 +99,12 @@ export const ExternalLinkEmbed = ({
function LinkWrapper({
link,
onOpen,
style,
children,
}: {
link: AppBskyEmbedExternal.ViewExternal
onOpen?: () => void
style?: StyleProp<ViewStyle>
children: React.ReactNode
}) {
@ -125,6 +129,7 @@ function LinkWrapper({
style,
]}
hoverStyle={t.atoms.border_contrast_high}
onBeforePress={onOpen}
onLongPress={onShareExternal}>
{children}
</Link>

View file

@ -42,9 +42,11 @@ import {PostEmbeds} from '.'
export function MaybeQuoteEmbed({
embed,
onOpen,
style,
}: {
embed: AppBskyEmbedRecord.View
onOpen?: () => void
style?: StyleProp<ViewStyle>
}) {
const pal = usePalette('default')
@ -57,6 +59,7 @@ export function MaybeQuoteEmbed({
<QuoteEmbedModerated
viewRecord={embed.record}
postRecord={embed.record.value}
onOpen={onOpen}
style={style}
/>
)
@ -85,10 +88,12 @@ export function MaybeQuoteEmbed({
function QuoteEmbedModerated({
viewRecord,
postRecord,
onOpen,
style,
}: {
viewRecord: AppBskyEmbedRecord.ViewRecord
postRecord: AppBskyFeedPost.Record
onOpen?: () => void
style?: StyleProp<ViewStyle>
}) {
const moderationOpts = useModerationOpts()
@ -108,16 +113,25 @@ function QuoteEmbedModerated({
embeds: viewRecord.embeds,
}
return <QuoteEmbed quote={quote} moderation={moderation} style={style} />
return (
<QuoteEmbed
quote={quote}
moderation={moderation}
onOpen={onOpen}
style={style}
/>
)
}
export function QuoteEmbed({
quote,
moderation,
onOpen,
style,
}: {
quote: ComposerOptsQuote
moderation?: ModerationDecision
onOpen?: () => void
style?: StyleProp<ViewStyle>
}) {
const queryClient = useQueryClient()
@ -150,7 +164,8 @@ export function QuoteEmbed({
const onBeforePress = React.useCallback(() => {
precacheProfile(queryClient, quote.author)
}, [queryClient, quote.author])
onOpen?.()
}, [queryClient, quote.author, onOpen])
return (
<ContentHider modui={moderation?.ui('contentList')}>

View file

@ -38,10 +38,12 @@ type Embed =
export function PostEmbeds({
embed,
moderation,
onOpen,
style,
}: {
embed?: Embed
moderation?: ModerationDecision
onOpen?: () => void
style?: StyleProp<ViewStyle>
}) {
const pal = usePalette('default')
@ -52,8 +54,12 @@ export function PostEmbeds({
if (AppBskyEmbedRecordWithMedia.isView(embed)) {
return (
<View style={style}>
<PostEmbeds embed={embed.media} moderation={moderation} />
<MaybeQuoteEmbed embed={embed.record} />
<PostEmbeds
embed={embed.media}
moderation={moderation}
onOpen={onOpen}
/>
<MaybeQuoteEmbed embed={embed.record} onOpen={onOpen} />
</View>
)
}
@ -80,7 +86,7 @@ export function PostEmbeds({
// quote post
// =
return <MaybeQuoteEmbed embed={embed} style={style} />
return <MaybeQuoteEmbed embed={embed} style={style} onOpen={onOpen} />
}
// image embed
@ -151,7 +157,7 @@ export function PostEmbeds({
const link = embed.external
return (
<ContentHider modui={moderation?.ui('contentMedia')}>
<ExternalLinkEmbed link={link} style={style} />
<ExternalLinkEmbed link={link} onOpen={onOpen} style={style} />
</ContentHider>
)
}