use profile card in immersive video

This commit is contained in:
Samuel Newman
2025-07-07 13:33:37 +03:00
parent 2b34721876
commit f47acbf949
+68 -72
View File
@@ -33,6 +33,7 @@ import {
AppBskyFeedPost, AppBskyFeedPost,
AtUri, AtUri,
type ModerationDecision, type ModerationDecision,
type ModerationOpts,
RichText as RichTextAPI, RichText as RichTextAPI,
} from '@atproto/api' } from '@atproto/api'
import {msg, Trans} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
@@ -54,7 +55,6 @@ import {
type CommonNavigatorParams, type CommonNavigatorParams,
type NavigationProp, type NavigationProp,
} from '#/lib/routes/types' } from '#/lib/routes/types'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {cleanError} from '#/lib/strings/errors' import {cleanError} from '#/lib/strings/errors'
import {sanitizeHandle} from '#/lib/strings/handles' import {sanitizeHandle} from '#/lib/strings/handles'
import {isAndroid} from '#/platform/detection' import {isAndroid} from '#/platform/detection'
@@ -70,6 +70,7 @@ import {
useFeedFeedbackContext, useFeedFeedbackContext,
} from '#/state/feed-feedback' } from '#/state/feed-feedback'
import {useFeedFeedback} from '#/state/feed-feedback' import {useFeedFeedback} from '#/state/feed-feedback'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {useFeedInfo} from '#/state/queries/feed' import {useFeedInfo} from '#/state/queries/feed'
import {usePostLikeMutationQueue} from '#/state/queries/post' import {usePostLikeMutationQueue} from '#/state/queries/post'
import { import {
@@ -95,10 +96,10 @@ import {EyeSlash_Stroke2_Corner0_Rounded as Eye} from '#/components/icons/EyeSla
import {Leaf_Stroke2_Corner0_Rounded as LeafIcon} from '#/components/icons/Leaf' import {Leaf_Stroke2_Corner0_Rounded as LeafIcon} from '#/components/icons/Leaf'
import {KeepAwake} from '#/components/KeepAwake' import {KeepAwake} from '#/components/KeepAwake'
import * as Layout from '#/components/Layout' import * as Layout from '#/components/Layout'
import {Link} from '#/components/Link'
import {ListFooter} from '#/components/Lists' import {ListFooter} from '#/components/Lists'
import * as Hider from '#/components/moderation/Hider' import * as Hider from '#/components/moderation/Hider'
import {PostControls} from '#/components/PostControls' import {PostControls} from '#/components/PostControls'
import * as ProfileCard from '#/components/ProfileCard'
import {RichText} from '#/components/RichText' import {RichText} from '#/components/RichText'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import * as bsky from '#/types/bsky' import * as bsky from '#/types/bsky'
@@ -189,6 +190,7 @@ function Feed() {
const isFocused = useIsFocused() const isFocused = useIsFocused()
const {hasSession} = useSession() const {hasSession} = useSession()
const {height} = useSafeAreaFrame() const {height} = useSafeAreaFrame()
const moderationOpts = useModerationOpts()
const feedDesc = useMemo(() => { const feedDesc = useMemo(() => {
switch (params.type) { switch (params.type) {
@@ -280,13 +282,21 @@ function Feed() {
} }
adjacent={index === currentIndex - 1 || index === currentIndex + 1} adjacent={index === currentIndex - 1 || index === currentIndex + 1}
moderation={item.moderation} moderation={item.moderation}
moderationOpts={moderationOpts}
scrollGesture={scrollGesture} scrollGesture={scrollGesture}
feedContext={item.feedContext} feedContext={item.feedContext}
reqId={item.reqId} reqId={item.reqId}
/> />
) )
}, },
[players, currentIndex, isFocused, currentSources, scrollGesture], [
players,
currentIndex,
isFocused,
currentSources,
scrollGesture,
moderationOpts,
],
) )
const updateVideoState = useCallback( const updateVideoState = useCallback(
@@ -478,6 +488,7 @@ let VideoItem = ({
adjacent, adjacent,
scrollGesture, scrollGesture,
moderation, moderation,
moderationOpts,
feedContext, feedContext,
reqId, reqId,
}: { }: {
@@ -488,6 +499,7 @@ let VideoItem = ({
adjacent: boolean adjacent: boolean
scrollGesture: NativeGesture scrollGesture: NativeGesture
moderation?: ModerationDecision moderation?: ModerationDecision
moderationOpts?: ModerationOpts
feedContext: string | undefined feedContext: string | undefined
reqId: string | undefined reqId: string | undefined
}): React.ReactNode => { }): React.ReactNode => {
@@ -548,6 +560,7 @@ let VideoItem = ({
active={active} active={active}
scrollGesture={scrollGesture} scrollGesture={scrollGesture}
moderation={moderation} moderation={moderation}
moderationOpts={moderationOpts}
feedContext={feedContext} feedContext={feedContext}
reqId={reqId} reqId={reqId}
/> />
@@ -694,6 +707,7 @@ function Overlay({
active, active,
scrollGesture, scrollGesture,
moderation, moderation,
moderationOpts,
feedContext, feedContext,
reqId, reqId,
}: { }: {
@@ -703,11 +717,11 @@ function Overlay({
active: boolean active: boolean
scrollGesture: NativeGesture scrollGesture: NativeGesture
moderation: ModerationDecision moderation: ModerationDecision
moderationOpts?: ModerationOpts
feedContext: string | undefined feedContext: string | undefined
reqId: string | undefined reqId: string | undefined
}) { }) {
const {_} = useLingui() const {_} = useLingui()
const t = useTheme()
const {openComposer} = useOpenComposer() const {openComposer} = useOpenComposer()
const {currentAccount} = useSession() const {currentAccount} = useSession()
const navigation = useNavigation<NavigationProp>() const navigation = useNavigation<NavigationProp>()
@@ -790,75 +804,57 @@ function Overlay({
]} ]}
style={[a.w_full, a.pt_md]}> style={[a.w_full, a.pt_md]}>
<Animated.View style={[a.px_md, animatedStyle]}> <Animated.View style={[a.px_md, animatedStyle]}>
<View style={[a.w_full, a.flex_row, a.align_center, a.gap_md]}> {moderationOpts && (
<Link <View style={[a.w_full, a.flex_row, a.align_center, a.gap_md]}>
label={_( <ProfileCard.Link profile={profile} style={[a.flex_1]}>
msg`View ${sanitizeDisplayName( <ProfileCard.Header>
post.author.displayName || post.author.handle, <ProfileCard.Avatar
)}'s profile`, profile={profile}
)} moderationOpts={moderationOpts}
to={{ />
screen: 'Profile', <ProfileCard.NameAndHandle
params: {name: post.author.did}, profile={profile}
}} moderationOpts={moderationOpts}
style={[a.flex_1, a.flex_row, a.gap_md, a.align_center]}> />
<UserAvatar </ProfileCard.Header>
type="user" </ProfileCard.Link>
avatar={post.author.avatar} {/* show button based on non-reactive version, so it doesn't hide on press */}
size={32} {post.author.did !== currentAccount?.did &&
/> !post.author.viewer?.following && (
<View style={[a.flex_1]}> <Button
<Text label={
style={[a.text_md, a.font_bold]} profile.viewer?.following
emoji ? _(msg`Following ${handle}`)
numberOfLines={1}> : _(msg`Follow ${handle}`)
{sanitizeDisplayName( }
post.author.displayName || post.author.handle, accessibilityHint={
)} profile.viewer?.following
</Text> ? _(msg`Unfollows the user`)
<Text : ''
style={[a.text_sm, t.atoms.text_contrast_high]} }
numberOfLines={1}> size="small"
{handle} variant="solid"
</Text> color="secondary_inverted"
</View> style={[a.mb_xs]}
</Link> onPress={() =>
{/* show button based on non-reactive version, so it doesn't hide on press */} profile.viewer?.following
{post.author.did !== currentAccount?.did && ? queueUnfollow()
!post.author.viewer?.following && ( : queueFollow()
<Button }>
label={ {!!profile.viewer?.following && (
profile.viewer?.following <ButtonIcon icon={CheckIcon} />
? _(msg`Following ${handle}`)
: _(msg`Follow ${handle}`)
}
accessibilityHint={
profile.viewer?.following
? _(msg`Unfollows the user`)
: ''
}
size="small"
variant="solid"
color="secondary_inverted"
style={[a.mb_xs]}
onPress={() =>
profile.viewer?.following
? queueUnfollow()
: queueFollow()
}>
{!!profile.viewer?.following && (
<ButtonIcon icon={CheckIcon} />
)}
<ButtonText>
{profile.viewer?.following ? (
<Trans>Following</Trans>
) : (
<Trans>Follow</Trans>
)} )}
</ButtonText> <ButtonText>
</Button> {profile.viewer?.following ? (
)} <Trans>Following</Trans>
</View> ) : (
<Trans>Follow</Trans>
)}
</ButtonText>
</Button>
)}
</View>
)}
{record?.text?.trim() && ( {record?.text?.trim() && (
<ExpandableRichTextView <ExpandableRichTextView
value={richText} value={richText}