From 1a1fee8918e181c3adeff0bb71566fa0b8cd4e97 Mon Sep 17 00:00:00 2001 From: thislight Date: Fri, 11 Oct 2024 21:26:02 +0800 Subject: [PATCH] first attempt of createTimeline in TimelinePanel - known bug: the paging is failed --- bun.lockb | Bin 240104 -> 240951 bytes package.json | 1 + src/masto/timelines.ts | 157 +++++++++++++++++++++++++++++++- src/timelines/TimelinePanel.tsx | 108 ++++++++++------------ 4 files changed, 202 insertions(+), 64 deletions(-) diff --git a/bun.lockb b/bun.lockb index 25e9097232174094867a4c68f2617eb664c3fb9d..3dc8a47b07cbc6f635b99e9a2042c30951072bd4 100755 GIT binary patch delta 42074 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 V`=R=BW6|qF)%}3W12uHd{{exS__F{2 diff --git a/package.json b/package.json index 19f3a48..e5a7f53 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "@solid-primitives/event-listener": "^2.3.3", "@solid-primitives/i18n": "^2.1.1", "@solid-primitives/intersection-observer": "^2.1.6", + "@solid-primitives/map": "^0.4.13", "@solid-primitives/resize-observer": "^2.0.26", "@solidjs/router": "^0.14.5", "@suid/icons-material": "^0.8.0", diff --git a/src/masto/timelines.ts b/src/masto/timelines.ts index e147cbc..06471df 100644 --- a/src/masto/timelines.ts +++ b/src/masto/timelines.ts @@ -1,5 +1,14 @@ +import { ReactiveMap } from "@solid-primitives/map"; import { type mastodon } from "masto"; -import { Accessor, catchError, createEffect, createResource } from "solid-js"; +import { + Accessor, + batch, + catchError, + createEffect, + createResource, + untrack, + type ResourceFetcherInfo, +} from "solid-js"; import { createStore } from "solid-js/store"; type TimelineFetchTips = { @@ -164,6 +173,148 @@ export function createTimelineSnapshot( ] as const; } -export function createTimeline(timeline: Accessor) { - // TODO +export type TimelineFetchDirection = mastodon.Direction; + +export type TimelineChunk = { + pager: mastodon.Paginator; + chunk: readonly mastodon.v1.Status[]; + done?: boolean; + direction: TimelineFetchDirection; + limit: number; +}; + +function checkOrCreatePager( + timeline: Timeline, + limit: number, + lastPager: TimelineChunk["pager"] | undefined, + newDirection: TimelineFetchDirection, +) { + if (!lastPager) { + return timeline.list({ }).setDirection(newDirection); + } else { + let pager = lastPager; + if (pager.getDirection() !== newDirection) { + pager = pager.setDirection(newDirection); + } + return pager; + } +} + +type TreeNode = { + parent?: TreeNode; + value: T; + children?: TreeNode[]; +}; + +/** Collect the path of a node for the root. + * The first element is the node itself, the last element is the root. + */ +function collectPath(node: TreeNode) { + const path = [node] as TreeNode[]; + let current = node; + while (current.parent) { + path.push(current.parent); + current = current.parent; + } + return path; +} + +export function createTimeline( + timeline: Accessor, + limit: Accessor, +) { + const lookup = new ReactiveMap>(); + const [threads, setThreads] = createStore([] as mastodon.v1.Status["id"][]); + + const [chunk, { refetch }] = createResource( + () => [timeline(), limit()] as const, + async ( + [tl, limit], + info: ResourceFetcherInfo< + Readonly, + TimelineFetchDirection + >, + ) => { + const direction = + typeof info.refetching === "boolean" ? "prev" : info.refetching; + const rebuildTimeline = limit !== info.value?.limit; + const pager = rebuildTimeline + ? checkOrCreatePager(tl, limit, undefined, direction) + : checkOrCreatePager(tl, limit, info.value?.pager, direction); + if (rebuildTimeline) { + lookup.clear(); + setThreads([]); + } + const posts = await pager.next(); + return { + pager, + chunk: posts.value ?? [], + done: posts.done, + direction, + limit, + }; + }, + ); + + createEffect(() => { + const chk = catchError(chunk, (e) => console.error(e)); + if (!chk) { + return; + } + console.debug("fetched chunk", chk); + + batch(() => { + for (const status of chk.chunk) { + lookup.set(status.id, { + value: status, + }); + } + + for (const status of chk.chunk) { + const node = lookup.get(status.id)!; + if (status.inReplyToId) { + const parent = lookup.get(status.inReplyToId); + if (parent) { + const children = parent.children ?? []; + if (!children.find((x) => x.value.id == status.id)) { + children.push(node); + } + parent.children = children; + node.parent = parent; + } + } + } + if (chk.direction === "next") { + setThreads((threads) => [...threads, ...chk.chunk.map((x) => x.id)]); + } else if (chk.direction === "prev") { + setThreads((threads) => [...chk.chunk.map((x) => x.id), ...threads]); + } + + setThreads((threads) => + threads.filter((id) => (lookup.get(id)!.children?.length ?? 0) === 0), + ); + }); + }); + + return [ + { + list: threads, + get(id: string) { + return lookup.get(id); + }, + getPath(id: string) { + const node = lookup.get(id); + if (!node) return; + return collectPath(node); + }, + set(id: string, value: mastodon.v1.Status) { + const node = untrack(() => lookup.get(id)); + if (!node) return; + node.value = value; + lookup.set(id, node); + }, + }, + chunk, + { refetch }, + ] as const; } diff --git a/src/timelines/TimelinePanel.tsx b/src/timelines/TimelinePanel.tsx index 04b8f46..ddafa87 100644 --- a/src/timelines/TimelinePanel.tsx +++ b/src/timelines/TimelinePanel.tsx @@ -10,19 +10,16 @@ import { ErrorBoundary, } from "solid-js"; import { type mastodon } from "masto"; -import { - Button, - LinearProgress, -} from "@suid/material"; -import TootThread from "./TootThread.js"; -import { useTimeline } from "../masto/timelines"; +import { Button, LinearProgress } from "@suid/material"; +import { createTimeline } from "../masto/timelines"; import { vibrate } from "../platform/hardware"; import PullDownToRefresh from "./PullDownToRefresh"; import TootComposer from "./TootComposer"; +import Thread from "./Thread.jsx"; const TimelinePanel: Component<{ client: mastodon.rest.Client; - name: "home" | "public" | "trends"; + name: "home" | "public"; prefetch?: boolean; fullRefetch?: number; @@ -33,70 +30,56 @@ const TimelinePanel: Component<{ ) => void; }> = (props) => { const [scrollLinked, setScrollLinked] = createSignal(); - const [ - timeline, - snapshot, - { refetch: refetchTimeline, mutate: mutateTimeline }, - ] = useTimeline( - () => - props.name !== "trends" - ? props.client.v1.timelines[props.name] - : props.client.v1.trends.statuses, - { fullRefresh: props.fullRefetch }, + + const [timeline, snapshot, { refetch: refetchTimeline }] = createTimeline( + () => props.client.v1.timelines[props.name], + () => 20, ); const [expandedThreadId, setExpandedThreadId] = createSignal(); const [typing, setTyping] = createSignal(false); const tlEndObserver = new IntersectionObserver(() => { if (untrack(() => props.prefetch) && !snapshot.loading) - refetchTimeline({ direction: "old" }); + refetchTimeline("next"); }); onCleanup(() => tlEndObserver.disconnect()); const onBookmark = async ( - index: number, client: mastodon.rest.Client, status: mastodon.v1.Status, ) => { const result = await (status.bookmarked ? client.v1.statuses.$select(status.id).unbookmark() : client.v1.statuses.$select(status.id).bookmark()); - mutateTimeline((o) => { - o[index] = result; - return o; - }); + timeline.set(result.id, result); }; const onBoost = async ( - index: number, client: mastodon.rest.Client, status: mastodon.v1.Status, ) => { - const reblogged = status.reblog - ? status.reblog.reblogged - : status.reblogged; vibrate(50); - mutateTimeline(index, (x) => { - if (x.reblog) { - x.reblog = { ...x.reblog, reblogged: !reblogged }; - return Object.assign({}, x); - } else { - return Object.assign({}, x, { + const rootStatus = status.reblog ? status.reblog : status; + const reblogged = rootStatus.reblogged; + if (status.reblog) { + status.reblog = { ...status.reblog, reblogged: !reblogged }; + timeline.set(status.id, status); + } else { + timeline.set( + status.id, + Object.assign(status, { reblogged: !reblogged, - }); - } - }); + }), + ); + } const result = reblogged ? await client.v1.statuses.$select(status.id).unreblog() : (await client.v1.statuses.$select(status.id).reblog()).reblog!; - mutateTimeline((o) => { - Object.assign(o[index].reblog ?? o[index], { - reblogged: result.reblogged, - reblogsCount: result.reblogsCount, - }); - return o; - }); + timeline.set( + status.id, + Object.assign(status.reblog ?? status, result.reblog), + ); }; return ( @@ -108,7 +91,7 @@ const TimelinePanel: Component<{ refetchTimeline({ direction: "new" })} + onRefresh={() => refetchTimeline("prev")} />
@@ -125,29 +108,32 @@ const TimelinePanel: Component<{ isTyping={typing()} onTypingChange={setTyping} client={props.client} - onSent={() => refetchTimeline({ direction: "new" })} + onSent={() => refetchTimeline("prev")} /> - - {(item, index) => { + + {(itemId, index) => { let element: HTMLElement | undefined; + const path = timeline.getPath(itemId)!; + const toots = path.reverse().map((x) => x.value); + return ( - onBoost(index(), ...args)} - onBookmark={(...args) => onBookmark(index(), ...args)} + toots={toots} + onBoost={onBoost} + onBookmark={onBookmark} onReply={(client, status) => props.openFullScreenToot(status, element, true) } client={props.client} - expanded={item.id === expandedThreadId() ? 1 : 0} - onExpandChange={(x) => { - setTyping(false) - if (item.id !== expandedThreadId()) { - setExpandedThreadId((x) => (x ? undefined : item.id)); - } else if (x === 2) { - props.openFullScreenToot(item, element); + isExpended={(status) => status.id === expandedThreadId()} + onItemClick={(status) => { + setTyping(false); + if (status.id !== expandedThreadId()) { + setExpandedThreadId((x) => (x ? undefined : status.id)); + } else { + props.openFullScreenToot(status, element); } }} /> @@ -179,7 +165,7 @@ const TimelinePanel: Component<{