Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

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

Remove `getProfile` calls when loading feed (#3881)

* remove unnecessary `getProfile()` calls from feed load

add comments

ensure only if first

simplify

nit

handle cases where the parent is removed

add a comment

remove unnecessary `getProfile()` calls from feed load

limit only to the first post in the returned items

move the logic out of the render and into the query

add the grandparent properly

update `FeedItem`

bump package

update `FeedItem`

update `post-feed` query

update `FeedSlice`

* nit

* simplify logic

* always pass `parentAuthor`

* oops!

* update `DebugMod`

authored by

Hailey and committed by
GitHub
70f190d4 6d647551

+78 -56
+7
src/state/queries/post-feed.ts
··· 1 1 import React, {useCallback, useEffect, useRef} from 'react' 2 2 import {AppState} from 'react-native' 3 3 import { 4 + AppBskyActorDefs, 4 5 AppBskyFeedDefs, 5 6 AppBskyFeedPost, 6 7 AtUri, ··· 72 73 reason?: AppBskyFeedDefs.ReasonRepost | ReasonFeedSource 73 74 feedContext: string | undefined 74 75 moderation: ModerationDecision 76 + parentAuthor?: AppBskyActorDefs.ProfileViewBasic 75 77 } 76 78 77 79 export interface FeedPostSlice { ··· 302 304 AppBskyFeedPost.validateRecord(item.post.record) 303 305 .success 304 306 ) { 307 + const parentAuthor = 308 + item.reply?.parent?.author ?? 309 + slice.items[i + 1]?.reply?.grandparentAuthor 310 + 305 311 return { 306 312 _reactKey: `${slice._reactKey}-${i}-${item.post.uri}`, 307 313 uri: item.post.uri, ··· 313 319 : item.reason, 314 320 feedContext: item.feedContext || slice.feedContext, 315 321 moderation: moderations[i], 322 + parentAuthor, 316 323 } 317 324 } 318 325 return undefined
+61 -56
src/view/com/posts/FeedItem.tsx
··· 1 1 import React, {memo, useMemo, useState} from 'react' 2 2 import {StyleSheet, View} from 'react-native' 3 3 import { 4 + AppBskyActorDefs, 4 5 AppBskyFeedDefs, 5 6 AppBskyFeedPost, 6 7 AtUri, ··· 40 41 import {PostMeta} from '../util/PostMeta' 41 42 import {Text} from '../util/text/Text' 42 43 import {PreviewableUserAvatar} from '../util/UserAvatar' 43 - import {UserInfoText} from '../util/UserInfoText' 44 + 45 + interface FeedItemProps { 46 + record: AppBskyFeedPost.Record 47 + reason: AppBskyFeedDefs.ReasonRepost | ReasonFeedSource | undefined 48 + moderation: ModerationDecision 49 + parentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined 50 + showReplyTo: boolean 51 + isThreadChild?: boolean 52 + isThreadLastChild?: boolean 53 + isThreadParent?: boolean 54 + feedContext: string | undefined 55 + } 44 56 45 57 export function FeedItem({ 46 58 post, ··· 48 60 reason, 49 61 feedContext, 50 62 moderation, 63 + parentAuthor, 64 + showReplyTo, 51 65 isThreadChild, 52 66 isThreadLastChild, 53 67 isThreadParent, 54 - }: { 55 - post: AppBskyFeedDefs.PostView 56 - record: AppBskyFeedPost.Record 57 - reason: AppBskyFeedDefs.ReasonRepost | ReasonFeedSource | undefined 58 - feedContext: string | undefined 59 - moderation: ModerationDecision 60 - isThreadChild?: boolean 61 - isThreadLastChild?: boolean 62 - isThreadParent?: boolean 63 - }) { 68 + }: FeedItemProps & {post: AppBskyFeedDefs.PostView}): React.ReactNode { 64 69 const postShadowed = usePostShadow(post) 65 70 const richText = useMemo( 66 71 () => ··· 83 88 reason={reason} 84 89 feedContext={feedContext} 85 90 richText={richText} 91 + parentAuthor={parentAuthor} 92 + showReplyTo={showReplyTo} 86 93 moderation={moderation} 87 94 isThreadChild={isThreadChild} 88 95 isThreadLastChild={isThreadLastChild} ··· 100 107 feedContext, 101 108 richText, 102 109 moderation, 110 + parentAuthor, 111 + showReplyTo, 103 112 isThreadChild, 104 113 isThreadLastChild, 105 114 isThreadParent, 106 - }: { 107 - post: Shadow<AppBskyFeedDefs.PostView> 108 - record: AppBskyFeedPost.Record 109 - reason: AppBskyFeedDefs.ReasonRepost | ReasonFeedSource | undefined 110 - feedContext: string | undefined 115 + }: FeedItemProps & { 111 116 richText: RichTextAPI 112 - moderation: ModerationDecision 113 - isThreadChild?: boolean 114 - isThreadLastChild?: boolean 115 - isThreadParent?: boolean 117 + post: Shadow<AppBskyFeedDefs.PostView> 116 118 }): React.ReactNode => { 117 119 const queryClient = useQueryClient() 118 120 const {openComposer} = useComposerControls() ··· 123 125 return makeProfileLink(post.author, 'post', urip.rkey) 124 126 }, [post.uri, post.author]) 125 127 const {sendInteraction} = useFeedFeedbackContext() 126 - 127 - const replyAuthorDid = useMemo(() => { 128 - if (!record?.reply) { 129 - return '' 130 - } 131 - const urip = new AtUri(record.reply.parent?.uri || record.reply.root.uri) 132 - return urip.hostname 133 - }, [record?.reply]) 134 128 135 129 const onPressReply = React.useCallback(() => { 136 130 sendInteraction({ ··· 318 312 postHref={href} 319 313 onOpenAuthor={onOpenAuthor} 320 314 /> 321 - {!isThreadChild && replyAuthorDid !== '' && ( 322 - <View style={[s.flexRow, s.mb2, s.alignCenter]}> 323 - <FontAwesomeIcon 324 - icon="reply" 325 - size={9} 326 - style={[ 327 - {color: pal.colors.textLight} as FontAwesomeIconStyle, 328 - s.mr5, 329 - ]} 330 - /> 331 - <Text 332 - type="md" 333 - style={[pal.textLight, s.mr2]} 334 - lineHeight={1.2} 335 - numberOfLines={1}> 336 - <Trans context="description"> 337 - Reply to{' '} 338 - <ProfileHoverCard inline did={replyAuthorDid}> 339 - <UserInfoText 340 - type="md" 341 - did={replyAuthorDid} 342 - attr="displayName" 343 - style={[pal.textLight]} 344 - /> 345 - </ProfileHoverCard> 346 - </Trans> 347 - </Text> 348 - </View> 315 + {!isThreadChild && showReplyTo && parentAuthor && ( 316 + <ReplyToLabel profile={parentAuthor} /> 349 317 )} 350 318 <LabelsOnMyPost post={post} /> 351 319 <PostContent ··· 433 401 ) 434 402 } 435 403 PostContent = memo(PostContent) 404 + 405 + function ReplyToLabel({profile}: {profile: AppBskyActorDefs.ProfileViewBasic}) { 406 + const pal = usePalette('default') 407 + 408 + return ( 409 + <View style={[s.flexRow, s.mb2, s.alignCenter]}> 410 + <FontAwesomeIcon 411 + icon="reply" 412 + size={9} 413 + style={[{color: pal.colors.textLight} as FontAwesomeIconStyle, s.mr5]} 414 + /> 415 + <Text 416 + type="md" 417 + style={[pal.textLight, s.mr2]} 418 + lineHeight={1.2} 419 + numberOfLines={1}> 420 + <Trans context="description"> 421 + Reply to{' '} 422 + <ProfileHoverCard inline did={profile.did}> 423 + <TextLinkOnWebOnly 424 + type="md" 425 + style={pal.textLight} 426 + lineHeight={1.2} 427 + numberOfLines={1} 428 + href={makeProfileLink(profile)} 429 + text={ 430 + profile.displayName 431 + ? sanitizeDisplayName(profile.displayName) 432 + : sanitizeHandle(profile.handle) 433 + } 434 + /> 435 + </ProfileHoverCard> 436 + </Trans> 437 + </Text> 438 + </View> 439 + ) 440 + } 436 441 437 442 const styles = StyleSheet.create({ 438 443 outer: {
+8
src/view/com/posts/FeedSlice.tsx
··· 22 22 record={slice.items[0].record} 23 23 reason={slice.items[0].reason} 24 24 feedContext={slice.items[0].feedContext} 25 + parentAuthor={slice.items[0].parentAuthor} 26 + showReplyTo={true} 25 27 moderation={slice.items[0].moderation} 26 28 isThreadParent={isThreadParentAt(slice.items, 0)} 27 29 isThreadChild={isThreadChildAt(slice.items, 0)} ··· 32 34 record={slice.items[1].record} 33 35 reason={slice.items[1].reason} 34 36 feedContext={slice.items[1].feedContext} 37 + parentAuthor={slice.items[1].parentAuthor} 38 + showReplyTo={false} 35 39 moderation={slice.items[1].moderation} 36 40 isThreadParent={isThreadParentAt(slice.items, 1)} 37 41 isThreadChild={isThreadChildAt(slice.items, 1)} ··· 43 47 record={slice.items[last].record} 44 48 reason={slice.items[last].reason} 45 49 feedContext={slice.items[last].feedContext} 50 + parentAuthor={slice.items[2].parentAuthor} 51 + showReplyTo={false} 46 52 moderation={slice.items[last].moderation} 47 53 isThreadParent={isThreadParentAt(slice.items, last)} 48 54 isThreadChild={isThreadChildAt(slice.items, last)} ··· 62 68 reason={slice.items[i].reason} 63 69 feedContext={slice.items[i].feedContext} 64 70 moderation={slice.items[i].moderation} 71 + parentAuthor={slice.items[i].parentAuthor} 72 + showReplyTo={i === 0} 65 73 isThreadParent={isThreadParentAt(slice.items, i)} 66 74 isThreadChild={isThreadChildAt(slice.items, i)} 67 75 isThreadLastChild={
+2
src/view/screens/DebugMod.tsx
··· 803 803 post={post} 804 804 record={post.record as AppBskyFeedPost.Record} 805 805 moderation={moderation} 806 + parentAuthor={undefined} 807 + showReplyTo={false} 806 808 reason={undefined} 807 809 feedContext={''} 808 810 />