nostros/frontend/Pages/MyFeed/index.tsx

215 lines
6.3 KiB
TypeScript
Raw Normal View History

2023-01-27 21:03:09 +00:00
import React, { useCallback, useContext, useState, useEffect } from 'react'
import { getUsers, User } from '../../Functions/DatabaseFunctions/Users'
import {
NativeScrollEvent,
NativeSyntheticEvent,
RefreshControl,
StyleSheet,
View,
} from 'react-native'
import { AppContext } from '../../Contexts/AppContext'
import { getLastReply, getMainNotes, Note } from '../../Functions/DatabaseFunctions/Notes'
import { handleInfinityScroll } from '../../Functions/NativeFunctions'
import { UserContext } from '../../Contexts/UserContext'
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
import { Kind } from 'nostr-tools'
import { RelayFilters } from '../../lib/nostr/RelayPool/intex'
import { ActivityIndicator, Button, Text } from 'react-native-paper'
import NoteCard from '../../Components/NoteCard'
import { useTheme } from '@react-navigation/native'
2023-02-03 09:37:54 +00:00
import { FlashList, ListRenderItem } from '@shopify/flash-list'
2023-01-27 21:03:09 +00:00
import { getLastReaction } from '../../Functions/DatabaseFunctions/Reactions'
2023-02-03 09:37:54 +00:00
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
import { useTranslation } from 'react-i18next'
2023-01-27 21:03:09 +00:00
interface MyFeedProps {
navigation: any
}
2023-02-03 16:33:08 +00:00
export const MyFeed: React.FC<MyFeedProps> = ({ navigation }) => {
2023-01-27 21:03:09 +00:00
const theme = useTheme()
2023-02-03 09:37:54 +00:00
const { t } = useTranslation('common')
2023-02-06 11:52:02 +00:00
const { database, pushedTab } = useContext(AppContext)
2023-01-27 21:03:09 +00:00
const { publicKey } = useContext(UserContext)
const { lastEventId, relayPool, lastConfirmationtId } = useContext(RelayPoolContext)
const initialPageSize = 10
const [notes, setNotes] = useState<Note[]>([])
const [pageSize, setPageSize] = useState<number>(initialPageSize)
const [refreshing, setRefreshing] = useState(false)
2023-02-06 11:52:02 +00:00
const flashListRef = React.useRef<FlashList<Note>>(null)
useEffect(() => {
if (pushedTab) {
flashListRef.current?.scrollToIndex({ animated: true, index: 0 })
}
}, [pushedTab])
2023-01-27 21:03:09 +00:00
useEffect(() => {
subscribeNotes()
loadNotes()
}, [])
useEffect(() => {
if (relayPool && publicKey) {
loadNotes()
}
}, [lastEventId, lastConfirmationtId])
useEffect(() => {
if (pageSize > initialPageSize) {
subscribeNotes(true)
}
}, [pageSize])
const onRefresh = useCallback(() => {
setRefreshing(true)
2023-02-09 22:10:50 +00:00
relayPool?.unsubscribe([
'homepage-contacts-main',
'homepage-contacts-meta',
'homepage-contacts-replies',
])
2023-01-27 21:03:09 +00:00
subscribeNotes()
}, [])
const subscribeNotes: (past?: boolean) => void = async (past) => {
if (!database || !publicKey) return
const users: User[] = await getUsers(database, { contacts: true, order: 'created_at DESC' })
const authors: string[] = [...users.map((user) => user.id), publicKey]
const message: RelayFilters = {
kinds: [Kind.Text, Kind.RecommendRelay],
authors,
limit: pageSize,
}
relayPool?.subscribe('homepage-contacts-main', [message])
setRefreshing(false)
}
const onScroll: (event: NativeSyntheticEvent<NativeScrollEvent>) => void = (event) => {
if (handleInfinityScroll(event)) {
setPageSize(pageSize + initialPageSize)
}
}
2023-02-06 11:10:11 +00:00
const loadNotes: () => void = async () => {
2023-01-27 21:03:09 +00:00
if (database && publicKey) {
2023-02-06 11:10:11 +00:00
getMainNotes(database, publicKey, pageSize, true).then(async (notes) => {
2023-01-27 21:03:09 +00:00
setNotes(notes)
if (notes.length > 0) {
2023-02-06 11:10:11 +00:00
const noteIds = notes.map((note) => note.id ?? '')
const messages: RelayFilters[] = [
2023-01-27 21:03:09 +00:00
{
kinds: [Kind.Metadata],
authors: notes.map((note) => note.pubkey ?? ''),
},
2023-02-06 11:10:11 +00:00
]
const lastReaction = await getLastReaction(database, {
eventIds: notes.map((note) => note.id ?? ''),
})
messages.push({
kinds: [Kind.Reaction],
'#e': noteIds,
since: lastReaction?.created_at ?? 0,
})
2023-01-29 21:46:34 +00:00
const repostIds = notes.filter((note) => note.repost_id).map((note) => note.id ?? '')
2023-02-06 08:27:39 +00:00
if (repostIds.length > 0) {
2023-02-06 11:10:11 +00:00
messages.push({
kinds: [Kind.Text],
'#e': repostIds,
})
2023-02-06 08:27:39 +00:00
}
2023-02-06 11:10:11 +00:00
relayPool?.subscribe('homepage-contacts-meta', messages)
const lastReply = await getLastReply(database, {
eventIds: notes.map((note) => note.id ?? ''),
})
relayPool?.subscribe('homepage-contacts-replies', [
{
kinds: [Kind.Text],
'#e': noteIds,
since: lastReply?.created_at ?? 0,
2023-01-27 21:03:09 +00:00
},
2023-02-06 11:10:11 +00:00
])
2023-01-27 21:03:09 +00:00
}
})
}
}
2023-01-29 21:54:40 +00:00
const renderItem: ListRenderItem<Note> = ({ item }) => {
2023-01-27 21:03:09 +00:00
return (
<View style={styles.noteCard} key={item.id}>
2023-02-03 16:33:08 +00:00
<NoteCard note={item} />
2023-01-27 21:03:09 +00:00
</View>
)
}
2023-02-03 09:37:54 +00:00
const ListEmptyComponent = React.useMemo(
() => (
<View style={styles.blank}>
<MaterialCommunityIcons
name='account-group-outline'
size={64}
style={styles.center}
color={theme.colors.onPrimaryContainer}
/>
<Text variant='headlineSmall' style={styles.center}>
{t('homeFeed.emptyTitle')}
</Text>
<Text variant='bodyMedium' style={styles.center}>
{t('homeFeed.emptyDescription')}
</Text>
<Button mode='contained' compact onPress={() => navigation.jumpTo('contacts')}>
{t('homeFeed.emptyButton')}
</Button>
</View>
),
[],
)
2023-01-27 21:03:09 +00:00
return (
2023-02-03 09:37:54 +00:00
<View style={styles.list}>
<FlashList
2023-02-03 13:35:42 +00:00
estimatedItemSize={200}
2023-02-03 09:37:54 +00:00
showsVerticalScrollIndicator={false}
data={notes}
renderItem={renderItem}
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />}
onScroll={onScroll}
refreshing={refreshing}
ListEmptyComponent={ListEmptyComponent}
horizontal={false}
2023-02-09 22:10:50 +00:00
ListFooterComponent={
notes.length > 0 ? <ActivityIndicator style={styles.loading} animating={true} /> : <></>
}
2023-02-06 11:52:02 +00:00
ref={flashListRef}
2023-02-03 09:37:54 +00:00
/>
2023-01-27 21:03:09 +00:00
</View>
)
}
const styles = StyleSheet.create({
2023-02-09 22:10:50 +00:00
loading: {
paddingTop: 16,
},
2023-02-03 09:37:54 +00:00
list: {
height: '100%',
},
2023-01-27 21:03:09 +00:00
noteCard: {
marginTop: 16,
},
center: {
alignContent: 'center',
textAlign: 'center',
},
blank: {
justifyContent: 'space-between',
height: 220,
marginTop: 91,
},
activityIndicator: {
padding: 16,
},
})
export default MyFeed