diff --git a/apps/renderer/src/atoms/settings/general.ts b/apps/renderer/src/atoms/settings/general.ts index e16703fe9..671ac46aa 100644 --- a/apps/renderer/src/atoms/settings/general.ts +++ b/apps/renderer/src/atoms/settings/general.ts @@ -10,6 +10,7 @@ const createDefaultSettings = (): GeneralSettings => ({ // Data control dataPersist: true, sendAnonymousData: true, + reduceRefetch: true, // view unreadOnly: false, diff --git a/apps/renderer/src/modules/entry-column/hooks.ts b/apps/renderer/src/modules/entry-column/hooks.ts index dade7a485..21d36de71 100644 --- a/apps/renderer/src/modules/entry-column/hooks.ts +++ b/apps/renderer/src/modules/entry-column/hooks.ts @@ -52,6 +52,7 @@ export const useEntryMarkReadHandler = (entriesIds: string[]) => { }, [feedView, handleMarkReadInRange, handleRenderAsRead, renderAsRead, scrollMarkUnread]) } const anyString = [] as string[] + export const useEntriesByView = ({ onReset, isArchived, diff --git a/apps/renderer/src/modules/settings/tabs/general.tsx b/apps/renderer/src/modules/settings/tabs/general.tsx index 7d73a9c15..141918ee5 100644 --- a/apps/renderer/src/modules/settings/tabs/general.tsx +++ b/apps/renderer/src/modules/settings/tabs/general.tsx @@ -80,6 +80,10 @@ export const SettingGeneral = () => { description: t("general.group_by_date.description"), }), + defineSettingItem("reduceRefetch", { + label: t("general.reduce_refetch.label"), + description: t("general.reduce_refetch.description"), + }), { type: "title", value: t("general.unread") }, defineSettingItem("scrollMarkUnread", { diff --git a/apps/renderer/src/providers/invalidate-query-provider.tsx b/apps/renderer/src/providers/invalidate-query-provider.tsx index e2abf9fab..7ce0ff998 100644 --- a/apps/renderer/src/providers/invalidate-query-provider.tsx +++ b/apps/renderer/src/providers/invalidate-query-provider.tsx @@ -3,9 +3,11 @@ import { IN_ELECTRON } from "@follow/shared/constants" import { useQueryClient } from "@tanstack/react-query" import { useEffect, useRef } from "react" +import { useGeneralSettingKey } from "~/atoms/settings/general" import { appLog } from "~/lib/log" -const slateTime = 600000 // 10min +const defaultSlateTime = 600_000 // 10min +const maxSlateTime = 6 * 60 * (60 * 1000) // 6hr export class ElectronCloseEvent extends Event { static type = "electron-close" @@ -20,6 +22,10 @@ export class ElectronShowEvent extends Event { } } +const useSlateTime = () => { + const reduceRefetch = useGeneralSettingKey("reduceRefetch") + return reduceRefetch ? maxSlateTime : defaultSlateTime +} /** * Add a event listener to invalidate all queries */ @@ -42,6 +48,8 @@ const InvalidateQueryProviderElectron = () => { } }, [queryClient]) + const slateTime = useSlateTime() + useEffect(() => { const handler = () => { const now = Date.now() @@ -82,6 +90,8 @@ const InvalidateQueryProviderWebApp = () => { const pageVisibility = usePageVisibility() + const slateTime = useSlateTime() + useEffect(() => { if (currentVisibilityRef.current === pageVisibility) { return diff --git a/apps/renderer/src/queries/entries.ts b/apps/renderer/src/queries/entries.ts index 19c21a496..50d7f42ab 100644 --- a/apps/renderer/src/queries/entries.ts +++ b/apps/renderer/src/queries/entries.ts @@ -1,3 +1,4 @@ +import { useGeneralSettingKey } from "~/atoms/settings/general" import { useAuthInfiniteQuery, useAuthQuery } from "~/hooks/common" import { apiClient } from "~/lib/api-fetch" import { defineQuery } from "~/lib/defineQuery" @@ -125,6 +126,9 @@ export const entries = { ), } +const maxStaleTime = 6 * 60 * (60 * 1000) // 6 hours +const defaultStaleTime = 10 * (60 * 1000) // 10 minutes + export const useEntries = ({ feedId, inboxId, @@ -139,17 +143,24 @@ export const useEntries = ({ view?: number read?: boolean isArchived?: boolean -}) => - useAuthInfiniteQuery(entries.entries({ feedId, inboxId, listId, view, read, isArchived }), { - enabled: feedId !== undefined || inboxId !== undefined || listId !== undefined, - getNextPageParam: (lastPage) => - inboxId || listId - ? lastPage.data?.at(-1)?.entries.insertedAt - : lastPage.data?.at(-1)?.entries.publishedAt, - initialPageParam: undefined, - refetchOnWindowFocus: false, - refetchOnReconnect: false, - }) +}) => { + const reduceRefetch = useGeneralSettingKey("reduceRefetch") + return useAuthInfiniteQuery( + entries.entries({ feedId, inboxId, listId, view, read, isArchived }), + { + enabled: feedId !== undefined || inboxId !== undefined || listId !== undefined, + getNextPageParam: (lastPage) => + inboxId || listId + ? lastPage.data?.at(-1)?.entries.insertedAt + : lastPage.data?.at(-1)?.entries.publishedAt, + initialPageParam: undefined, + refetchOnWindowFocus: false, + refetchOnReconnect: false, + + staleTime: reduceRefetch ? maxStaleTime : defaultStaleTime, + }, + ) +} export const useEntriesPreview = ({ id }: { id?: string }) => useAuthQuery(entries.preview(id!), { diff --git a/apps/server/client/atoms/settings/general.ts b/apps/server/client/atoms/settings/general.ts index a73925500..d81c273a2 100644 --- a/apps/server/client/atoms/settings/general.ts +++ b/apps/server/client/atoms/settings/general.ts @@ -1,9 +1,8 @@ import type { GeneralSettings } from "@follow/shared/interface/settings" -import { jotaiStore } from "../../lib/store" import { createSettingAtom } from "./helper" -const createDefaultSettings = (): GeneralSettings => ({ +const createDefaultSettings = (): Partial => ({ // App appLaunchOnStartup: false, language: "en", @@ -22,6 +21,7 @@ const createDefaultSettings = (): GeneralSettings => ({ groupByDate: true, // Secure jumpOutLinkWarn: true, + voice: "", }) export const { @@ -36,9 +36,6 @@ export const { settingAtom: __generalSettingAtom, } = createSettingAtom("general", createDefaultSettings) -export const subscribeShouldUseIndexedDB = (callback: (value: boolean) => void) => - jotaiStore.sub(__generalSettingAtom, () => callback(getGeneralSettings().dataPersist)) - export const generalServerSyncWhiteListKeys: (keyof GeneralSettings)[] = [ "appLaunchOnStartup", "dataPersist", diff --git a/changelog/next.md b/changelog/next.md index d4812057e..c1d46de03 100644 --- a/changelog/next.md +++ b/changelog/next.md @@ -12,6 +12,7 @@ - Optimized the Zen mode experience on macOS. - Improvement web app global shortcuts. +- Optimized the Timeline's data cache, reducing data reloads within a short period of time. You can go to Settings -> General -> Timeline -> Reduce timeline refetch to control this feature, default is enabled. ## Bug Fixes diff --git a/locales/settings/en.json b/locales/settings/en.json index 093673589..7258f8bd9 100644 --- a/locales/settings/en.json +++ b/locales/settings/en.json @@ -138,6 +138,8 @@ "general.rebuild_database.title": "Rebuild Database", "general.rebuild_database.warning.line1": "Rebuilding the database will clear all your local data.", "general.rebuild_database.warning.line2": "Are you sure you want to continue?", + "general.reduce_refetch.description": "Reduce the data refetch of Timeline, to avoid Timeline being refreshed again when switching between different views.", + "general.reduce_refetch.label": "Reduce timeline refetch", "general.send_anonymous_data.description": "By opting to send anonymized telemetry data, you contribute to improving the overall user experience of Follow.", "general.send_anonymous_data.label": "Send anonymous data", "general.show_unread_on_launch.description": "Show unread content on launch", diff --git a/packages/shared/src/interface/settings.ts b/packages/shared/src/interface/settings.ts index 597048808..5063e9bf2 100644 --- a/packages/shared/src/interface/settings.ts +++ b/packages/shared/src/interface/settings.ts @@ -11,6 +11,7 @@ export interface GeneralSettings { jumpOutLinkWarn: boolean // TTS voice: string + reduceRefetch: boolean } export interface UISettings {