Stream update timelines
This commit is contained in:
parent
f829339d7b
commit
c16742b6e0
|
@ -1,11 +1,14 @@
|
|||
import { Account } from '@/db'
|
||||
import { TextInput } from 'flowbite-react'
|
||||
import { Entity, MegalodonInterface } from 'megalodon'
|
||||
import { useEffect, useState, useCallback } from 'react'
|
||||
import generator, { Entity, MegalodonInterface, WebSocketInterface } from 'megalodon'
|
||||
import { useEffect, useState, useCallback, useRef } from 'react'
|
||||
import { Virtuoso } from 'react-virtuoso'
|
||||
import Status from './status/Status'
|
||||
import { FormattedMessage, useIntl } from 'react-intl'
|
||||
|
||||
const TIMELINE_STATUSES_COUNT = 3
|
||||
const TIMELINE_MAX_STATUSES = 2147483647
|
||||
|
||||
type Props = {
|
||||
timeline: string
|
||||
account: Account
|
||||
|
@ -13,15 +16,56 @@ type Props = {
|
|||
}
|
||||
export default function Timeline(props: Props) {
|
||||
const [statuses, setStatuses] = useState<Array<Entity.Status>>([])
|
||||
const [unreads, setUnreads] = useState<Array<Entity.Status>>([])
|
||||
const [firstItemIndex, setFirstItemIndex] = useState(TIMELINE_MAX_STATUSES)
|
||||
|
||||
const { formatMessage } = useIntl()
|
||||
const scrollerRef = useRef<HTMLElement | null>(null)
|
||||
const streaming = useRef<WebSocketInterface | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const f = async () => {
|
||||
const res = await loadTimeline(props.timeline, props.client)
|
||||
setStatuses(res)
|
||||
const instance = await props.client.getInstance()
|
||||
const c = generator(props.account.sns, instance.data.urls.streaming_api, props.account.access_token, 'Whalebird')
|
||||
switch (props.timeline) {
|
||||
case 'home': {
|
||||
streaming.current = c.userSocket()
|
||||
break
|
||||
}
|
||||
case 'local': {
|
||||
streaming.current = c.localSocket()
|
||||
break
|
||||
}
|
||||
case 'public': {
|
||||
streaming.current = c.publicSocket()
|
||||
break
|
||||
}
|
||||
}
|
||||
if (streaming.current) {
|
||||
streaming.current.on('connect', () => {
|
||||
console.log(`connected to ${props.timeline}`)
|
||||
})
|
||||
streaming.current.on('update', (status: Entity.Status) => {
|
||||
if (scrollerRef.current && scrollerRef.current.scrollTop > 10) {
|
||||
setUnreads(current => [status, ...current])
|
||||
} else {
|
||||
setStatuses(current => [status, ...current])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
f()
|
||||
}, [props.timeline, props.client])
|
||||
|
||||
return () => {
|
||||
if (streaming.current) {
|
||||
streaming.current.removeAllListeners()
|
||||
streaming.current.stop()
|
||||
console.log(`closed ${props.timeline}`)
|
||||
}
|
||||
}
|
||||
}, [props.timeline, props.client, props.account])
|
||||
|
||||
const loadTimeline = async (tl: string, client: MegalodonInterface, maxId?: string): Promise<Array<Entity.Status>> => {
|
||||
let options = { limit: 30 }
|
||||
|
@ -72,6 +116,16 @@ export default function Timeline(props: Props) {
|
|||
setStatuses(last => [...last, ...append])
|
||||
}, [props.client, statuses, setStatuses])
|
||||
|
||||
const prependUnreads = useCallback(() => {
|
||||
console.debug('prepending')
|
||||
const u = unreads.slice().reverse().slice(0, TIMELINE_STATUSES_COUNT).reverse()
|
||||
const remains = u.slice(0, -1 * TIMELINE_STATUSES_COUNT)
|
||||
setUnreads(() => remains)
|
||||
setFirstItemIndex(() => firstItemIndex - u.length)
|
||||
setStatuses(() => [...u, ...statuses])
|
||||
return false
|
||||
}, [firstItemIndex, statuses, setStatuses, unreads])
|
||||
|
||||
return (
|
||||
<section className="h-full w-full">
|
||||
<div className="w-full bg-blue-950 text-blue-100 p-2 flex justify-between">
|
||||
|
@ -87,6 +141,11 @@ export default function Timeline(props: Props) {
|
|||
<div className="timeline overflow-y-auto w-full overflow-x-hidden" style={{ height: 'calc(100% - 50px)' }}>
|
||||
<Virtuoso
|
||||
style={{ height: '100%' }}
|
||||
scrollerRef={ref => {
|
||||
scrollerRef.current = ref as HTMLElement
|
||||
}}
|
||||
firstItemIndex={firstItemIndex}
|
||||
atTopStateChange={prependUnreads}
|
||||
data={statuses}
|
||||
endReached={loadMore}
|
||||
itemContent={(_, status) => (
|
||||
|
|
Loading…
Reference in New Issue