feat: 💨

This commit is contained in:
codytseng 2025-12-01 00:16:52 +08:00
parent 7ec4835c61
commit a6c41d8d3f
2 changed files with 335 additions and 276 deletions

View file

@ -92,6 +92,8 @@ export default function NormalFeed({
showKinds={temporaryShowKinds}
subRequests={subRequests}
filterFn={filterFn}
areAlgoRelays={areAlgoRelays}
showRelayCloseReason={showRelayCloseReason}
/>
) : (
<NoteList

View file

@ -12,6 +12,7 @@ import { useDeletedEvent } from '@/providers/DeletedEventProvider'
import { useMuteList } from '@/providers/MuteListProvider'
import { useNostr } from '@/providers/NostrProvider'
import { usePinnedUsers } from '@/providers/PinnedUsersProvider'
import { useReply } from '@/providers/ReplyProvider'
import { useUserTrust } from '@/providers/UserTrustProvider'
import client from '@/services/client.service'
import userAggregationService, { TUserAggregation } from '@/services/user-aggregation.service'
@ -30,7 +31,9 @@ import {
} from 'react'
import { useTranslation } from 'react-i18next'
import PullToRefresh from 'react-simple-pull-to-refresh'
import { toast } from 'sonner'
import { LoadingBar } from '../LoadingBar'
import NewNotesButton from '../NewNotesButton'
const LIMIT = 500
const SHOW_COUNT = 20
@ -47,8 +50,21 @@ const UserAggregationList = forwardRef<
showKinds?: number[]
filterFn?: (event: Event) => boolean
filterMutedNotes?: boolean
areAlgoRelays?: boolean
showRelayCloseReason?: boolean
}
>(({ subRequests, showKinds, filterFn, filterMutedNotes = true }, ref) => {
>(
(
{
subRequests,
showKinds,
filterFn,
filterMutedNotes = true,
areAlgoRelays = false,
showRelayCloseReason = false
},
ref
) => {
const { t } = useTranslation()
const { startLogin } = useNostr()
const { push } = useSecondaryPage()
@ -57,8 +73,10 @@ const UserAggregationList = forwardRef<
const { pinnedPubkeySet } = usePinnedUsers()
const { hideContentMentioningMutedUsers } = useContentPolicy()
const { isEventDeleted } = useDeletedEvent()
const { addReplies } = useReply()
const [since, setSince] = useState(() => dayjs().subtract(1, 'day').unix())
const [events, setEvents] = useState<Event[]>([])
const [newEvents, setNewEvents] = useState<Event[]>([])
const [timelineKey, setTimelineKey] = useState<string | undefined>(undefined)
const [loading, setLoading] = useState(true)
const [showLoadingBar, setShowLoadingBar] = useState(true)
@ -102,9 +120,12 @@ const UserAggregationList = forwardRef<
async function init() {
setLoading(true)
setEvents([])
setNewEvents([])
setHasMore(true)
if (showKinds?.length === 0 && subRequests.every(({ filter }) => !filter.kinds)) {
setLoading(false)
setHasMore(false)
return () => {}
}
@ -122,25 +143,42 @@ const UserAggregationList = forwardRef<
if (events.length > 0) {
setEvents(events)
}
if (eosed) {
setLoading(false)
if (events.length === 0) {
if (areAlgoRelays) {
setHasMore(false)
}
if (eosed) {
setLoading(false)
setHasMore(events.length > 0)
addReplies(events)
}
},
onNew: (event) => {
setEvents((oldEvents) => {
const newEvents = oldEvents.some((e) => e.id === event.id)
? oldEvents
: [event, ...oldEvents]
return newEvents
})
setNewEvents((oldEvents) =>
[event, ...oldEvents].sort((a, b) => b.created_at - a.created_at)
)
addReplies([event])
},
onClose: (url, reason) => {
if (!showRelayCloseReason) return
// ignore reasons from nostr-tools
if (
[
'closed by caller',
'relay connection errored',
'relay connection closed',
'pingpong timed out',
'relay connection closed by us'
].includes(reason)
) {
return
}
toast.error(`${url}: ${reason}`)
}
},
{
startLogin,
needSort: true
needSort: !areAlgoRelays
}
)
setTimelineKey(timelineKey)
@ -218,6 +256,10 @@ const UserAggregationList = forwardRef<
return events.filter((evt) => evt.created_at >= since && !shouldHideEvent(evt))
}, [events, since, shouldHideEvent])
const filteredNewEvents = useMemo(() => {
return newEvents.filter((evt) => evt.created_at >= since && !shouldHideEvent(evt))
}, [newEvents, since, shouldHideEvent])
const aggregations = useMemo(() => {
const aggs = userAggregationService.aggregateByUser(filteredEvents)
userAggregationService.saveAggregations(feedId, aggs)
@ -286,6 +328,14 @@ const UserAggregationList = forwardRef<
setShowCount(SHOW_COUNT)
}
const showNewEvents = () => {
setEvents((oldEvents) => [...newEvents, ...oldEvents])
setNewEvents([])
setTimeout(() => {
scrollToTop('smooth')
}, 0)
}
const list = (
<div className="min-h-screen">
{pinnedAggregations.map((agg) => (
@ -329,7 +379,9 @@ const UserAggregationList = forwardRef<
<div className="border-b h-12 pl-4 pr-1 flex items-center justify-between gap-2">
<div className="text-sm text-muted-foreground flex items-center gap-1.5 min-w-0">
<span className="font-medium text-foreground">
{lastXDays === 1 ? t('Last 24 hours') : t('Last {{count}} days', { count: lastXDays })}
{lastXDays === 1
? t('Last 24 hours')
: t('Last {{count}} days', { count: lastXDays })}
</span>
·
<span>
@ -359,9 +411,14 @@ const UserAggregationList = forwardRef<
) : (
list
)}
<div className="h-40" />
{filteredNewEvents.length > 0 && (
<NewNotesButton newEvents={filteredNewEvents} onClick={showNewEvents} />
)}
</div>
)
})
}
)
UserAggregationList.displayName = 'UserAggregationList'
export default UserAggregationList