WIP need to fix types

This commit is contained in:
Eric Bailey
2025-01-18 12:24:30 -06:00
parent 5effcf8442
commit e0aaf18e59
+199 -118
View File
@@ -48,6 +48,8 @@ import {
} from '@react-navigation/native' } from '@react-navigation/native'
import {NativeStackScreenProps} from '@react-navigation/native-stack' import {NativeStackScreenProps} from '@react-navigation/native-stack'
import {EyeSlash_Stroke2_Corner0_Rounded as Eye} from '#/components/icons/EyeSlash'
import * as Hider from '#/components/moderation/Hider'
import {HITSLOP_20} from '#/lib/constants' import {HITSLOP_20} from '#/lib/constants'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped' import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped'
@@ -151,7 +153,7 @@ export function VideoFeed({}: NativeStackScreenProps<
type CurrentSource = { type CurrentSource = {
source: string source: string
moderation?: ModerationDecision moderation: ModerationDecision
} | null } | null
function Feed() { function Feed() {
@@ -208,6 +210,8 @@ function Feed() {
const renderItem: ListRenderItem<FeedPostSliceItem> = useCallback( const renderItem: ListRenderItem<FeedPostSliceItem> = useCallback(
({item, index}) => { ({item, index}) => {
const {post} = item const {post} = item
// filtered above, here for TS
if (!post.embed || !AppBskyEmbedVideo.isView(post.embed)) { if (!post.embed || !AppBskyEmbedVideo.isView(post.embed)) {
return null return null
} }
@@ -215,6 +219,10 @@ function Feed() {
const player = players?.[index % 3] const player = players?.[index % 3]
const currentSource = currentSources[index % 3] const currentSource = currentSources[index % 3]
if (!currentSource?.moderation) {
return null
}
return ( return (
<VideoItem <VideoItem
player={player} player={player}
@@ -225,7 +233,7 @@ function Feed() {
index === currentIndex && index === currentIndex &&
currentSource?.source === post.embed.playlist currentSource?.source === post.embed.playlist
} }
moderation={currentSource?.moderation} moderation={currentSource.moderation}
scrollGesture={scrollGesture} scrollGesture={scrollGesture}
/> />
) )
@@ -445,7 +453,7 @@ function VideoItem({
embed: AppBskyEmbedVideo.View embed: AppBskyEmbedVideo.View
active: boolean active: boolean
scrollGesture: NativeGesture scrollGesture: NativeGesture
moderation?: ModerationDecision moderation: ModerationDecision
}) { }) {
const postShadow = usePostShadow(post) const postShadow = usePostShadow(post)
const {width, height} = useSafeAreaFrame() const {width, height} = useSafeAreaFrame()
@@ -495,6 +503,7 @@ function VideoItem({
<Overlay <Overlay
player={player} player={player}
post={postShadow} post={postShadow}
embed={embed}
active={active} active={active}
scrollGesture={scrollGesture} scrollGesture={scrollGesture}
moderation={moderation} moderation={moderation}
@@ -538,18 +547,67 @@ function VideoItemInner({
) )
} }
function ModerationOverlay({
embed,
onPressShow,
}: {
embed: AppBskyEmbedVideo.View
onPressShow: () => void
}) {
const hider = Hider.useHider()
const {_} = useLingui()
const onShow = React.useCallback(() => {
hider.setIsContentVisible(true)
onPressShow()
}, [hider])
return (
<View style={[a.absolute, a.inset_0, a.z_20]}>
<VideoItemPlaceholder blur embed={embed} />
<View
style={[
a.absolute,
a.inset_0,
a.z_20,
a.justify_center,
a.align_center,
]}>
<View style={[a.align_center, a.gap_sm]}>
<Eye width={36} fill="white" />
<Text style={[a.text_center, a.leading_snug, a.pb_xs]}>
<Trans>Hidden by your moderation settings.</Trans>
</Text>
<Button
label={_(msg`Show anyway`)}
size="small"
variant="solid"
color="secondary_inverted"
onPress={onShow}>
<ButtonText>
<Trans>Show anyway</Trans>
</ButtonText>
</Button>
</View>
</View>
</View>
)
}
function Overlay({ function Overlay({
player, player,
post, post,
embed,
active, active,
scrollGesture, scrollGesture,
}: // moderation moderation,
{ }: {
player?: VideoPlayer player?: VideoPlayer
post: Shadow<AppBskyFeedDefs.PostView> post: Shadow<AppBskyFeedDefs.PostView>
embed: AppBskyEmbedVideo.View
active: boolean active: boolean
scrollGesture: NativeGesture scrollGesture: NativeGesture
moderation?: ModerationDecision moderation: ModerationDecision
}) { }) {
const {_} = useLingui() const {_} = useLingui()
const t = useTheme() const t = useTheme()
@@ -574,122 +632,137 @@ function Overlay({
})) }))
return ( return (
<> <Hider.Outer modui={moderation.ui('contentView')}>
<View style={[a.absolute, a.inset_0, a.z_20]}> <Hider.Mask>
<View style={[a.flex_1]}> <ModerationOverlay
<PlayPauseTapArea player={player} post={post} /> embed={embed}
</View> onPressShow={() => {
player?.play()
}}
/>
</Hider.Mask>
<Hider.Content>
<View style={[a.absolute, a.inset_0, a.z_20]}>
<View style={[a.flex_1]}>
<PlayPauseTapArea player={player} post={post} />
</View>
<LinearGradient <LinearGradient
colors={['rgba(0,0,0,0)', 'rgba(0,0,0,0.8)', 'rgba(0,0,0,0.95)']} colors={['rgba(0,0,0,0)', 'rgba(0,0,0,0.8)', 'rgba(0,0,0,0.95)']}
style={[a.w_full, a.pt_md]}> style={[a.w_full, a.pt_md]}>
<Animated.View style={[a.px_xl, animatedStyle]}> <Animated.View style={[a.px_xl, animatedStyle]}>
<View style={[a.w_full, a.flex_row, a.align_center, a.gap_md]}> <View style={[a.w_full, a.flex_row, a.align_center, a.gap_md]}>
<Link <Link
label={_( label={_(
msg`View ${sanitizeDisplayName( msg`View ${sanitizeDisplayName(
post.author.displayName || post.author.handle,
)}'s profile`,
)}
to={{
screen: 'Profile',
params: {name: post.author.did},
}}
style={[
a.flex_1,
a.flex_row,
a.gap_md,
a.pb_sm,
a.align_center,
]}>
<UserAvatar type="user" avatar={post.author.avatar} size={32} />
<View style={[a.flex_1]}>
<Text
style={[a.text_md, a.font_heavy]}
emoji
numberOfLines={1}>
{sanitizeDisplayName(
post.author.displayName || post.author.handle, post.author.displayName || post.author.handle,
)} )}'s profile`,
</Text>
<Text
style={[a.text_sm, t.atoms.text_contrast_high]}
numberOfLines={1}>
{sanitizeHandle(post.author.handle, '@')}
</Text>
</View>
</Link>
{/* show button based on non-reactive version, so it doesn't hide on press */}
{!post.author.viewer?.following && (
<Button
label={
profile.viewer?.following
? _(msg`Following`)
: _(msg`Follow`)
}
accessibilityHint={
profile.viewer?.following ? _(msg`Unfollow user`) : ''
}
size="small"
variant="outline"
color="secondary_inverted"
style={[a.mb_xs, a.bg_transparent]}
hoverStyle={[]}
onPress={() =>
profile.viewer?.following ? queueUnfollow() : queueFollow()
}>
{!!profile.viewer?.following && (
<ButtonIcon icon={CheckIcon} />
)} )}
<ButtonText> to={{
{profile.viewer?.following ? ( screen: 'Profile',
<Trans>Following</Trans> params: {name: post.author.did},
) : ( }}
<Trans>Follow</Trans> style={[
a.flex_1,
a.flex_row,
a.gap_md,
a.pb_sm,
a.align_center,
]}>
<UserAvatar
type="user"
avatar={post.author.avatar}
size={32}
/>
<View style={[a.flex_1]}>
<Text
style={[a.text_md, a.font_heavy]}
emoji
numberOfLines={1}>
{sanitizeDisplayName(
post.author.displayName || post.author.handle,
)}
</Text>
<Text
style={[a.text_sm, t.atoms.text_contrast_high]}
numberOfLines={1}>
{sanitizeHandle(post.author.handle, '@')}
</Text>
</View>
</Link>
{/* show button based on non-reactive version, so it doesn't hide on press */}
{!post.author.viewer?.following && (
<Button
label={
profile.viewer?.following
? _(msg`Following`)
: _(msg`Follow`)
}
accessibilityHint={
profile.viewer?.following ? _(msg`Unfollow user`) : ''
}
size="small"
variant="outline"
color="secondary_inverted"
style={[a.mb_xs, a.bg_transparent]}
hoverStyle={[]}
onPress={() =>
profile.viewer?.following
? queueUnfollow()
: queueFollow()
}>
{!!profile.viewer?.following && (
<ButtonIcon icon={CheckIcon} />
)} )}
</ButtonText> <ButtonText>
</Button> {profile.viewer?.following ? (
<Trans>Following</Trans>
) : (
<Trans>Follow</Trans>
)}
</ButtonText>
</Button>
)}
</View>
{record?.text?.trim() && (
<View style={[a.pb_sm]}>
<ExpandableRichTextView
value={richText}
authorHandle={post.author.handle}
/>
</View>
)} )}
</View> {record && (
{record?.text?.trim() && ( <View style={[{left: -5}]}>
<View style={[a.pb_sm]}> <PostCtrls
<ExpandableRichTextView richText={richText}
value={richText} post={post}
authorHandle={post.author.handle} record={record}
/> logContext="FeedItem"
</View> onPressReply={() =>
)} navigation.navigate('PostThread', {
{record && ( name: post.author.did,
<View style={[{left: -5}]}> rkey,
<PostCtrls })
richText={richText} }
post={post} big
record={record} />
logContext="FeedItem" </View>
onPressReply={() => )}
navigation.navigate('PostThread', { </Animated.View>
name: post.author.did,
rkey,
})
}
big
/>
</View>
)}
</Animated.View>
{player && active ? ( {player && active ? (
<Scrubber <Scrubber
player={player} player={player}
seekingAnimationSV={seekingAnimationSV} seekingAnimationSV={seekingAnimationSV}
scrollGesture={scrollGesture} scrollGesture={scrollGesture}
/> />
) : ( ) : (
<ScrubberPlaceholder /> <ScrubberPlaceholder />
)} )}
</LinearGradient> </LinearGradient>
</View> </View>
{/* {/*
{isAndroid && status === 'loading' && ( {isAndroid && status === 'loading' && (
<View <View
style={[ style={[
@@ -704,7 +777,8 @@ function Overlay({
</View> </View>
)} )}
*/} */}
</> </Hider.Content>
</Hider.Outer>
) )
} }
@@ -954,17 +1028,24 @@ function ExpandableRichTextView({
function VideoItemPlaceholder({ function VideoItemPlaceholder({
embed, embed,
style, style,
blur,
}: { }: {
embed: AppBskyEmbedVideo.View embed: AppBskyEmbedVideo.View
style?: ImageStyle style?: ImageStyle
blur?: boolean
}) { }) {
const src = embed.thumbnail const src = embed.thumbnail
let contentFit = isTallAspectRatio(embed.aspectRatio) ? 'cover' : 'contain'
if (blur) {
contentFit = 'cover'
}
return src ? ( return src ? (
<Image <Image
accessibilityIgnoresInvertColors accessibilityIgnoresInvertColors
source={{uri: src}} source={{uri: src}}
style={[a.absolute, a.inset_0, style]} style={[a.absolute, a.inset_0, style]}
contentFit={isTallAspectRatio(embed.aspectRatio) ? 'cover' : 'contain'} contentFit={contentFit}
blurRadius={blur ? 40 : 0}
/> />
) : null ) : null
} }