2020-12-12 22:19:18 +01:00
|
|
|
import React, { useCallback, useEffect, useMemo, useRef } from 'react'
|
2020-12-18 23:58:53 +01:00
|
|
|
import { StyleSheet } from 'react-native'
|
|
|
|
import { useInfiniteQuery } from 'react-query'
|
2020-10-23 09:22:17 +02:00
|
|
|
|
2020-12-13 14:04:25 +01:00
|
|
|
import TimelineNotifications from '@components/Timelines/Timeline/Notifications'
|
|
|
|
import TimelineDefault from '@components/Timelines/Timeline/Default'
|
|
|
|
import TimelineConversation from '@components/Timelines/Timeline/Conversation'
|
|
|
|
import { timelineFetch } from '@utils/fetches/timelineFetch'
|
|
|
|
import TimelineSeparator from '@components/Timelines/Timeline/Separator'
|
|
|
|
import TimelineEmpty from '@components/Timelines/Timeline/Empty'
|
|
|
|
import TimelineEnd from '@components/Timelines/Timeline/Shared/End'
|
2020-12-13 23:02:54 +01:00
|
|
|
import { useScrollToTop } from '@react-navigation/native'
|
2020-12-17 12:04:58 +01:00
|
|
|
import { FlatList } from 'react-native-gesture-handler'
|
2020-10-24 18:07:09 +02:00
|
|
|
|
2020-11-04 22:26:38 +01:00
|
|
|
export interface Props {
|
2020-11-21 00:40:55 +01:00
|
|
|
page: App.Pages
|
2020-10-31 21:04:46 +01:00
|
|
|
hashtag?: string
|
|
|
|
list?: string
|
2020-12-12 12:49:29 +01:00
|
|
|
toot?: Mastodon.Status
|
2020-10-31 21:04:46 +01:00
|
|
|
account?: string
|
|
|
|
disableRefresh?: boolean
|
2020-11-04 22:26:38 +01:00
|
|
|
}
|
2020-10-23 09:22:17 +02:00
|
|
|
|
2020-11-04 22:26:38 +01:00
|
|
|
const Timeline: React.FC<Props> = ({
|
|
|
|
page,
|
|
|
|
hashtag,
|
|
|
|
list,
|
|
|
|
toot,
|
|
|
|
account,
|
2020-12-18 00:00:45 +01:00
|
|
|
disableRefresh = false
|
2020-11-04 22:26:38 +01:00
|
|
|
}) => {
|
2020-12-18 23:58:53 +01:00
|
|
|
const queryKey: QueryKey.Timeline = [
|
2020-12-13 00:22:49 +01:00
|
|
|
page,
|
|
|
|
{
|
|
|
|
page,
|
|
|
|
...(hashtag && { hashtag }),
|
|
|
|
...(list && { list }),
|
|
|
|
...(toot && { toot }),
|
|
|
|
...(account && { account })
|
|
|
|
}
|
|
|
|
]
|
2020-11-04 22:26:38 +01:00
|
|
|
const {
|
2020-12-13 01:24:25 +01:00
|
|
|
status,
|
2020-11-04 22:26:38 +01:00
|
|
|
data,
|
2020-12-18 23:58:53 +01:00
|
|
|
refetch,
|
|
|
|
hasPreviousPage,
|
|
|
|
fetchPreviousPage,
|
|
|
|
isFetchingPreviousPage,
|
|
|
|
hasNextPage,
|
|
|
|
fetchNextPage,
|
|
|
|
isFetchingNextPage
|
2020-12-12 18:22:22 +01:00
|
|
|
} = useInfiniteQuery(queryKey, timelineFetch, {
|
2020-12-18 23:58:53 +01:00
|
|
|
getPreviousPageParam: firstPage => ({
|
|
|
|
direction: 'prev',
|
|
|
|
id: firstPage.toots[0].id
|
|
|
|
}),
|
|
|
|
getNextPageParam: lastPage =>
|
|
|
|
lastPage.toots.length
|
|
|
|
? {
|
|
|
|
direction: 'next',
|
|
|
|
id: lastPage.toots[lastPage.toots.length - 1].id
|
|
|
|
}
|
|
|
|
: undefined
|
2020-12-12 18:22:22 +01:00
|
|
|
})
|
2020-12-18 23:58:53 +01:00
|
|
|
const flattenData = data?.pages ? data.pages.flatMap(d => [...d?.toots]) : []
|
|
|
|
const flattenPointer = data?.pages
|
|
|
|
? data.pages.flatMap(d => [d?.pointer])
|
|
|
|
: []
|
|
|
|
const flattenPinnedLength = data?.pages
|
|
|
|
? data.pages.flatMap(d => [d?.pinnedLength])
|
|
|
|
: []
|
2020-12-12 12:49:29 +01:00
|
|
|
|
2020-12-17 12:04:58 +01:00
|
|
|
const flRef = useRef<FlatList<any>>(null)
|
2020-12-12 12:49:29 +01:00
|
|
|
useEffect(() => {
|
2020-12-18 23:58:53 +01:00
|
|
|
if (toot && status === 'success') {
|
2020-12-12 12:49:29 +01:00
|
|
|
setTimeout(() => {
|
|
|
|
flRef.current?.scrollToIndex({
|
2020-12-14 23:44:57 +01:00
|
|
|
index: flattenPointer[0]!,
|
2020-12-12 12:49:29 +01:00
|
|
|
viewOffset: 100
|
|
|
|
})
|
|
|
|
}, 500)
|
|
|
|
}
|
2020-12-18 23:58:53 +01:00
|
|
|
}, [status])
|
2020-10-23 09:22:17 +02:00
|
|
|
|
2020-11-28 17:07:30 +01:00
|
|
|
const flKeyExtrator = useCallback(({ id }) => id, [])
|
2020-12-14 23:44:57 +01:00
|
|
|
const flRenderItem = useCallback(({ item, index }) => {
|
2020-11-28 17:07:30 +01:00
|
|
|
switch (page) {
|
|
|
|
case 'Conversations':
|
2020-12-13 00:22:49 +01:00
|
|
|
return <TimelineConversation item={item} queryKey={queryKey} />
|
2020-11-28 17:07:30 +01:00
|
|
|
case 'Notifications':
|
|
|
|
return <TimelineNotifications notification={item} queryKey={queryKey} />
|
|
|
|
default:
|
2020-12-12 22:19:18 +01:00
|
|
|
return (
|
|
|
|
<TimelineDefault
|
|
|
|
item={item}
|
|
|
|
queryKey={queryKey}
|
2020-12-14 23:44:57 +01:00
|
|
|
index={index}
|
|
|
|
{...(flattenPinnedLength &&
|
|
|
|
flattenPinnedLength[0] && {
|
|
|
|
pinnedLength: flattenPinnedLength[0]
|
|
|
|
})}
|
2020-12-12 22:19:18 +01:00
|
|
|
{...(toot && toot.id === item.id && { highlighted: true })}
|
|
|
|
/>
|
|
|
|
)
|
2020-11-28 17:07:30 +01:00
|
|
|
}
|
|
|
|
}, [])
|
2020-12-12 22:19:18 +01:00
|
|
|
const flItemSeparatorComponent = useCallback(
|
|
|
|
({ leadingItem }) => (
|
|
|
|
<TimelineSeparator
|
|
|
|
{...(toot && toot.id === leadingItem.id && { highlighted: true })}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
[]
|
|
|
|
)
|
|
|
|
const flItemEmptyComponent = useMemo(
|
2020-12-13 01:24:25 +01:00
|
|
|
() => <TimelineEmpty status={status} refetch={refetch} />,
|
2020-12-18 23:58:53 +01:00
|
|
|
[status]
|
2020-12-12 22:19:18 +01:00
|
|
|
)
|
2020-11-28 17:07:30 +01:00
|
|
|
const flOnRefresh = useCallback(
|
2020-12-18 23:58:53 +01:00
|
|
|
() => !disableRefresh && fetchPreviousPage(),
|
|
|
|
[]
|
2020-11-28 17:07:30 +01:00
|
|
|
)
|
2020-12-18 23:58:53 +01:00
|
|
|
const flOnEndReach = useCallback(() => fetchNextPage(), [])
|
2020-12-12 12:49:29 +01:00
|
|
|
const flFooter = useCallback(() => {
|
2020-12-18 23:58:53 +01:00
|
|
|
return <TimelineEnd hasNextPage={hasNextPage} />
|
|
|
|
}, [hasNextPage])
|
2020-12-12 12:49:29 +01:00
|
|
|
const onScrollToIndexFailed = useCallback(error => {
|
|
|
|
const offset = error.averageItemLength * error.index
|
|
|
|
flRef.current?.scrollToOffset({ offset })
|
|
|
|
setTimeout(
|
|
|
|
() =>
|
|
|
|
flRef.current?.scrollToIndex({ index: error.index, viewOffset: 100 }),
|
|
|
|
350
|
2020-10-26 00:27:53 +01:00
|
|
|
)
|
2020-12-12 12:49:29 +01:00
|
|
|
}, [])
|
2020-10-23 09:22:17 +02:00
|
|
|
|
2020-12-13 23:02:54 +01:00
|
|
|
useScrollToTop(flRef)
|
|
|
|
|
2020-12-12 12:49:29 +01:00
|
|
|
return (
|
|
|
|
<FlatList
|
|
|
|
ref={flRef}
|
|
|
|
data={flattenData}
|
|
|
|
style={styles.flatList}
|
|
|
|
onRefresh={flOnRefresh}
|
|
|
|
renderItem={flRenderItem}
|
|
|
|
onEndReached={flOnEndReach}
|
|
|
|
keyExtractor={flKeyExtrator}
|
2020-12-12 22:19:18 +01:00
|
|
|
ListFooterComponent={flFooter}
|
2020-12-18 23:58:53 +01:00
|
|
|
refreshing={isFetchingPreviousPage}
|
2020-12-12 22:19:18 +01:00
|
|
|
ListEmptyComponent={flItemEmptyComponent}
|
2020-12-12 12:49:29 +01:00
|
|
|
ItemSeparatorComponent={flItemSeparatorComponent}
|
|
|
|
onEndReachedThreshold={!disableRefresh ? 0.75 : null}
|
2020-12-18 23:58:53 +01:00
|
|
|
{...(toot && status === 'success' && { onScrollToIndexFailed })}
|
2020-12-12 12:49:29 +01:00
|
|
|
/>
|
|
|
|
)
|
2020-10-23 09:22:17 +02:00
|
|
|
}
|
|
|
|
|
2020-11-28 17:07:30 +01:00
|
|
|
const styles = StyleSheet.create({
|
|
|
|
flatList: {
|
|
|
|
minHeight: '100%'
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2020-10-31 21:04:46 +01:00
|
|
|
export default Timeline
|