diff options
Diffstat (limited to 'src/screens/VideoFeed/components/Header.tsx')
-rw-r--r-- | src/screens/VideoFeed/components/Header.tsx | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/src/screens/VideoFeed/components/Header.tsx b/src/screens/VideoFeed/components/Header.tsx new file mode 100644 index 000000000..66c932119 --- /dev/null +++ b/src/screens/VideoFeed/components/Header.tsx @@ -0,0 +1,180 @@ +import {useCallback} from 'react' +import {GestureResponderEvent, View} from 'react-native' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useNavigation} from '@react-navigation/native' + +import {HITSLOP_30} from '#/lib/constants' +import {NavigationProp} from '#/lib/routes/types' +import {sanitizeHandle} from '#/lib/strings/handles' +import {useFeedSourceInfoQuery} from '#/state/queries/feed' +import {UserAvatar} from '#/view/com/util/UserAvatar' +import {VideoFeedSourceContext} from '#/screens/VideoFeed/types' +import {atoms as a, useBreakpoints} from '#/alf' +import {Button, ButtonProps} from '#/components/Button' +import {ArrowLeft_Stroke2_Corner0_Rounded as ArrowLeft} from '#/components/icons/Arrow' +import * as Layout from '#/components/Layout' +import {BUTTON_VISUAL_ALIGNMENT_OFFSET} from '#/components/Layout/const' +import {Text} from '#/components/Typography' + +export function HeaderPlaceholder() { + return ( + <View style={[a.flex_1, a.flex_row, a.align_center, a.gap_sm]}> + <View + style={[ + a.rounded_sm, + { + width: 36, + height: 36, + backgroundColor: 'white', + opacity: 0.8, + }, + ]} + /> + + <View style={[a.flex_1, a.gap_xs]}> + <View + style={[ + a.w_full, + a.rounded_xs, + { + backgroundColor: 'white', + height: 14, + width: 80, + opacity: 0.8, + }, + ]} + /> + <View + style={[ + a.w_full, + a.rounded_xs, + { + backgroundColor: 'white', + height: 10, + width: 140, + opacity: 0.6, + }, + ]} + /> + </View> + </View> + ) +} + +export function Header({ + sourceContext, +}: { + sourceContext: VideoFeedSourceContext +}) { + let content = null + switch (sourceContext.type) { + case 'feedgen': { + content = <FeedHeader sourceContext={sourceContext} /> + break + } + case 'author': + // TODO + default: { + break + } + } + + return ( + <Layout.Header.Outer noBottomBorder> + <BackButton /> + <Layout.Header.Content align="left">{content}</Layout.Header.Content> + </Layout.Header.Outer> + ) +} + +export function FeedHeader({ + sourceContext, +}: { + sourceContext: Exclude<VideoFeedSourceContext, {type: 'author'}> +}) { + const {gtMobile} = useBreakpoints() + + const { + data: info, + isLoading, + error, + } = useFeedSourceInfoQuery({uri: sourceContext.uri}) + + if (sourceContext.sourceInterstitial !== undefined) { + // For now, don't show the header if coming from an interstitial. + return null + } + + if (isLoading) { + return <HeaderPlaceholder /> + } else if (error || !info) { + return null + } + + return ( + <View style={[a.flex_1, a.flex_row, a.align_center, a.gap_sm]}> + {info.avatar && <UserAvatar size={36} type="algo" avatar={info.avatar} />} + + <View style={[a.flex_1]}> + <Text + style={[ + a.text_md, + a.font_heavy, + a.leading_tight, + gtMobile && a.text_lg, + ]} + numberOfLines={2}> + {info.displayName} + </Text> + <View style={[a.flex_row, {gap: 6}]}> + <Text + style={[a.flex_shrink, a.text_sm, a.leading_snug]} + numberOfLines={1}> + {sanitizeHandle(info.creatorHandle, '@')} + </Text> + </View> + </View> + </View> + ) +} + +// TODO: This customization should be a part of the layout component +export function BackButton({onPress, style, ...props}: Partial<ButtonProps>) { + const {_} = useLingui() + const navigation = useNavigation<NavigationProp>() + + const onPressBack = useCallback( + (evt: GestureResponderEvent) => { + onPress?.(evt) + if (evt.defaultPrevented) return + if (navigation.canGoBack()) { + navigation.goBack() + } else { + navigation.navigate('Home') + } + }, + [onPress, navigation], + ) + + return ( + <Layout.Header.Slot> + <Button + label={_(msg`Go back`)} + size="small" + variant="ghost" + color="secondary" + shape="round" + onPress={onPressBack} + hitSlop={HITSLOP_30} + style={[ + {marginLeft: -BUTTON_VISUAL_ALIGNMENT_OFFSET}, + a.bg_transparent, + style, + ]} + {...props}> + <ArrowLeft size="lg" fill="white" /> + </Button> + </Layout.Header.Slot> + ) +} |