From 2d75ecfbe33bb0c7245187429ad692c4af91e3d6 Mon Sep 17 00:00:00 2001 From: thislight Date: Tue, 6 Aug 2024 20:27:30 +0800 Subject: [PATCH] useTimeline: use store to provide partial editing --- src/masto/timelines.ts | 44 +++++++++++++++++++++++++++------------ src/platform/hardware.ts | 6 ++++++ src/timelines/Home.tsx | 45 +++++++++++++++++++++++++--------------- 3 files changed, 65 insertions(+), 30 deletions(-) create mode 100644 src/platform/hardware.ts diff --git a/src/masto/timelines.ts b/src/masto/timelines.ts index 91e1d84..55d1276 100644 --- a/src/masto/timelines.ts +++ b/src/masto/timelines.ts @@ -1,5 +1,6 @@ import { type mastodon } from "masto"; -import { Accessor, createResource, createSignal } from "solid-js"; +import { Accessor, createEffect, createResource, createSignal } from "solid-js"; +import { createStore } from "solid-js/store"; type TimelineFetchTips = { direction?: "new" | "old"; @@ -17,8 +18,8 @@ export function useTimeline(timeline: Accessor) { let maxId: string | undefined; let otl: Timeline | undefined; const idSet = new Set(); - return createResource< - mastodon.v1.Status[], + const [snapshot, { refetch }] = createResource< + { records: mastodon.v1.Status[]; direction: "old" | "new" }, [Timeline], TimelineFetchTips | undefined >( @@ -28,7 +29,6 @@ export function useTimeline(timeline: Accessor) { minId = undefined; maxId = undefined; idSet.clear(); - info.value = []; otl = tl; } const direction = @@ -44,7 +44,6 @@ export function useTimeline(timeline: Accessor) { minId: maxId, }, ); - const old = info.value || []; const diff = pager.filter((x) => !idSet.has(x.id)); for (const v of diff.map((x) => x.id)) { idSet.add(v); @@ -54,20 +53,39 @@ export function useTimeline(timeline: Accessor) { if (!maxId && pager.length > 0) { maxId = pager[0].id; } - return [...old, ...diff]; + return { + direction: "old" as const, + records: diff, + }; } else { maxId = pager.length > 0 ? pager[0].id : undefined; if (!minId && pager.length > 0) { minId = pager[pager.length - 1]?.id; } - return [...diff, ...old]; + return { direction: "new" as const, records: diff }; } }, - { - initialValue: [], - storage(init) { - return createSignal(init, { equals: false }); - }, - }, ); + + const [store, setStore] = createStore([] as mastodon.v1.Status[]); + + createEffect(() => { + const shot = snapshot(); + if (!shot) return; + const { direction, records } = shot; + if (direction == "new") { + setStore((x) => [...records, ...x]); + } else if (direction == "old") { + setStore((x) => [...x, ...records]); + } + }); + + return [ + store, + snapshot, + { + refetch, + mutate: setStore, + }, + ] as const; } diff --git a/src/platform/hardware.ts b/src/platform/hardware.ts new file mode 100644 index 0000000..2d1d0d6 --- /dev/null +++ b/src/platform/hardware.ts @@ -0,0 +1,6 @@ +export function vibrate(pattern: number | number[]) { + if (typeof navigator.vibrate !== "undefined") { + return navigator.vibrate(pattern); + } + return false; +} diff --git a/src/timelines/Home.tsx b/src/timelines/Home.tsx index 44682e1..2a193f0 100644 --- a/src/timelines/Home.tsx +++ b/src/timelines/Home.tsx @@ -37,21 +37,25 @@ import { makeEventListener } from "@solid-primitives/event-listener"; import BottomSheet from "../material/BottomSheet"; import { $settings } from "../settings/stores"; import { useStore } from "@nanostores/solid"; +import { vibrate } from "../platform/hardware"; const TimelinePanel: Component<{ client: mastodon.rest.Client; name: "home" | "public" | "trends"; prefetch?: boolean; }> = (props) => { - const [timeline, { refetch: refetchTimeline, mutate: mutateTimeline }] = - useTimeline(() => - props.name !== "trends" - ? props.client.v1.timelines[props.name] - : props.client.v1.trends.statuses, - ); + const [ + timeline, + snapshot, + { refetch: refetchTimeline, mutate: mutateTimeline }, + ] = useTimeline(() => + props.name !== "trends" + ? props.client.v1.timelines[props.name] + : props.client.v1.trends.statuses, + ); const tlEndObserver = new IntersectionObserver(() => { - if (untrack(() => props.prefetch) && !timeline.loading) + if (untrack(() => props.prefetch) && !snapshot.loading) refetchTimeline({ direction: "old" }); }); @@ -76,12 +80,19 @@ const TimelinePanel: Component<{ client: mastodon.rest.Client, status: mastodon.v1.Status, ) => { - const reblogged = false; - mutateTimeline((o) => { - Object.assign(o[index].reblog ?? o[index], { - reblogged: !reblogged, - }); - return o; + 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, { + reblogged: !reblogged, + }); + } }); const result = reblogged ? await client.v1.statuses.$select(status.id).unreblog() @@ -98,7 +109,7 @@ const TimelinePanel: Component<{ return ( <>
- + {(item, index) => { return (
tlEndObserver.observe(e)}>
- +
- +
- +