end card
This commit is contained in:
@@ -20,6 +20,7 @@ export function ListFooter({
|
|||||||
style,
|
style,
|
||||||
showEndMessage = false,
|
showEndMessage = false,
|
||||||
endMessageText,
|
endMessageText,
|
||||||
|
renderEndMessage,
|
||||||
}: {
|
}: {
|
||||||
isFetchingNextPage?: boolean
|
isFetchingNextPage?: boolean
|
||||||
hasNextPage?: boolean
|
hasNextPage?: boolean
|
||||||
@@ -29,6 +30,7 @@ export function ListFooter({
|
|||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
showEndMessage?: boolean
|
showEndMessage?: boolean
|
||||||
endMessageText?: string
|
endMessageText?: string
|
||||||
|
renderEndMessage?: () => React.ReactNode
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
|
||||||
@@ -48,9 +50,13 @@ export function ListFooter({
|
|||||||
) : error ? (
|
) : error ? (
|
||||||
<ListFooterMaybeError error={error} onRetry={onRetry} />
|
<ListFooterMaybeError error={error} onRetry={onRetry} />
|
||||||
) : !hasNextPage && showEndMessage ? (
|
) : !hasNextPage && showEndMessage ? (
|
||||||
|
renderEndMessage ? (
|
||||||
|
renderEndMessage()
|
||||||
|
) : (
|
||||||
<Text style={[a.text_sm, t.atoms.text_contrast_low]}>
|
<Text style={[a.text_sm, t.atoms.text_contrast_low]}>
|
||||||
{endMessageText ?? <Trans>You have reached the end</Trans>}
|
{endMessageText ?? <Trans>You have reached the end</Trans>}
|
||||||
</Text>
|
</Text>
|
||||||
|
)
|
||||||
) : null}
|
) : null}
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import {HITSLOP_20} from '#/lib/constants'
|
|||||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||||
import {CommonNavigatorParams, NavigationProp} from '#/lib/routes/types'
|
import {CommonNavigatorParams, NavigationProp} from '#/lib/routes/types'
|
||||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||||
|
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'
|
||||||
import {POST_TOMBSTONE, Shadow, usePostShadow} from '#/state/cache/post-shadow'
|
import {POST_TOMBSTONE, Shadow, usePostShadow} from '#/state/cache/post-shadow'
|
||||||
@@ -73,6 +74,7 @@ import {Header} from '#/screens/VideoFeed/components/Header'
|
|||||||
import {atoms as a, platform, ThemeProvider, useTheme} from '#/alf'
|
import {atoms as a, platform, ThemeProvider, useTheme} from '#/alf'
|
||||||
import {setNavigationBar} from '#/alf/util/navigationBar'
|
import {setNavigationBar} from '#/alf/util/navigationBar'
|
||||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||||
|
import {ArrowLeft_Stroke2_Corner0_Rounded as ArrowLeftIcon} from '#/components/icons/Arrow'
|
||||||
import {Check_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Check'
|
import {Check_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Check'
|
||||||
import * as Layout from '#/components/Layout'
|
import * as Layout from '#/components/Layout'
|
||||||
import {Link} from '#/components/Link'
|
import {Link} from '#/components/Link'
|
||||||
@@ -146,6 +148,8 @@ function Feed() {
|
|||||||
const {params} = useRoute<RouteProp<CommonNavigatorParams, 'VideoFeed'>>()
|
const {params} = useRoute<RouteProp<CommonNavigatorParams, 'VideoFeed'>>()
|
||||||
const isFocused = useIsFocused()
|
const isFocused = useIsFocused()
|
||||||
const {hasSession} = useSession()
|
const {hasSession} = useSession()
|
||||||
|
const {height} = useSafeAreaFrame()
|
||||||
|
|
||||||
const feedDesc = useMemo(() => {
|
const feedDesc = useMemo(() => {
|
||||||
switch (params.type) {
|
switch (params.type) {
|
||||||
case 'feedgen':
|
case 'feedgen':
|
||||||
@@ -159,14 +163,9 @@ function Feed() {
|
|||||||
}
|
}
|
||||||
}, [params])
|
}, [params])
|
||||||
const feedFeedback = useFeedFeedback(feedDesc, hasSession)
|
const feedFeedback = useFeedFeedback(feedDesc, hasSession)
|
||||||
const {
|
const {data, error, hasNextPage, isFetchingNextPage, fetchNextPage} =
|
||||||
data,
|
usePostFeedQuery(feedDesc)
|
||||||
isFetching,
|
|
||||||
refetch,
|
|
||||||
hasNextPage,
|
|
||||||
isFetchingNextPage,
|
|
||||||
fetchNextPage,
|
|
||||||
} = usePostFeedQuery(feedDesc)
|
|
||||||
const videos = React.useMemo(() => {
|
const videos = React.useMemo(() => {
|
||||||
let vids =
|
let vids =
|
||||||
data?.pages
|
data?.pages
|
||||||
@@ -343,6 +342,8 @@ function Feed() {
|
|||||||
[updateVideoState],
|
[updateVideoState],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const renderEndMessage = useCallback(() => <EndMessage />, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FeedFeedbackProvider value={feedFeedback}>
|
<FeedFeedbackProvider value={feedFeedback}>
|
||||||
<GestureDetector gesture={scrollGesture}>
|
<GestureDetector gesture={scrollGesture}>
|
||||||
@@ -351,13 +352,16 @@ function Feed() {
|
|||||||
renderItem={renderItem}
|
renderItem={renderItem}
|
||||||
keyExtractor={keyExtractor}
|
keyExtractor={keyExtractor}
|
||||||
pagingEnabled={true}
|
pagingEnabled={true}
|
||||||
refreshing={isFetching}
|
|
||||||
onRefresh={refetch}
|
|
||||||
ListFooterComponent={
|
ListFooterComponent={
|
||||||
<ListFooter
|
<ListFooter
|
||||||
hasNextPage={hasNextPage}
|
hasNextPage={hasNextPage}
|
||||||
isFetchingNextPage={isFetchingNextPage}
|
isFetchingNextPage={isFetchingNextPage}
|
||||||
onRetry={refetch}
|
error={cleanError(error)}
|
||||||
|
onRetry={fetchNextPage}
|
||||||
|
height={height}
|
||||||
|
showEndMessage
|
||||||
|
renderEndMessage={renderEndMessage}
|
||||||
|
style={[a.justify_center]}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
onEndReached={() => {
|
onEndReached={() => {
|
||||||
@@ -762,6 +766,60 @@ function PlayPauseTapArea({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function EndMessage() {
|
||||||
|
const navigation = useNavigation<NavigationProp>()
|
||||||
|
const {_} = useLingui()
|
||||||
|
const t = useTheme()
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
a.w_full,
|
||||||
|
a.gap_2xl,
|
||||||
|
a.px_lg,
|
||||||
|
a.mx_auto,
|
||||||
|
a.align_center,
|
||||||
|
{maxWidth: 350},
|
||||||
|
]}>
|
||||||
|
<View style={[a.w_full, a.gap_md]}>
|
||||||
|
<Text style={[a.text_3xl, a.text_center, a.font_heavy]}>
|
||||||
|
<Trans>That's everything!</Trans>
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
a.text_lg,
|
||||||
|
a.text_center,
|
||||||
|
t.atoms.text_contrast_high,
|
||||||
|
a.leading_snug,
|
||||||
|
]}>
|
||||||
|
<Trans>
|
||||||
|
You've run out of videos to watch. Maybe it's a good time to take a
|
||||||
|
break?
|
||||||
|
</Trans>
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<Button
|
||||||
|
testID="videoFeedGoBackButton"
|
||||||
|
onPress={() => {
|
||||||
|
if (navigation.canGoBack()) {
|
||||||
|
navigation.goBack()
|
||||||
|
} else {
|
||||||
|
navigation.navigate('Home')
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
variant="solid"
|
||||||
|
color="secondary_inverted"
|
||||||
|
size="small"
|
||||||
|
label={_(msg`Go back`)}
|
||||||
|
accessibilityHint={_(msg`Returns to previous page`)}>
|
||||||
|
<ButtonIcon icon={ArrowLeftIcon} />
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Go back</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the video is taller than 9:16
|
* If the video is taller than 9:16
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user