From 5f2cf8f20e47ce4643e3feb5bcf7a6735b32deb9 Mon Sep 17 00:00:00 2001 From: DIYgod Date: Mon, 10 Feb 2025 17:09:41 +0800 Subject: [PATCH] feat: seprate listIds and inboxIds with feedIds in subscription store --- .../entry-column/layouts/TimelineTabs.tsx | 12 +---- .../src/modules/feed-column/list.desktop.tsx | 19 +------ apps/renderer/src/store/subscription/hooks.ts | 46 +++++----------- .../src/store/subscription/selector.ts | 16 ++---- apps/renderer/src/store/subscription/store.ts | 52 +++++++++++-------- 5 files changed, 50 insertions(+), 95 deletions(-) diff --git a/apps/renderer/src/modules/entry-column/layouts/TimelineTabs.tsx b/apps/renderer/src/modules/entry-column/layouts/TimelineTabs.tsx index 5ec7c9217..a69bab8b4 100644 --- a/apps/renderer/src/modules/entry-column/layouts/TimelineTabs.tsx +++ b/apps/renderer/src/modules/entry-column/layouts/TimelineTabs.tsx @@ -11,18 +11,10 @@ export const TimelineTabs = () => { const { view, listId, inboxId, folderName } = routerParams const listsData = useSubscriptionStore( - useCallback( - (state) => - state.feedIdByView[view].map((id) => state.data[id]).filter((s) => s && "listId" in s), - [view], - ), + useCallback((state) => Array.from(state.listIds).map((id) => state.data[id]), []), ) const inboxData = useSubscriptionStore( - useCallback( - (state) => - state.feedIdByView[view].map((id) => state.data[id]).filter((s) => s && "inboxId" in s), - [view], - ), + useCallback((state) => Array.from(state.inboxIds).map((id) => state.data[id]), []), ) const categoriesData = useSubscriptionStore( useCallback( diff --git a/apps/renderer/src/modules/feed-column/list.desktop.tsx b/apps/renderer/src/modules/feed-column/list.desktop.tsx index a8c40f544..55d060c83 100644 --- a/apps/renderer/src/modules/feed-column/list.desktop.tsx +++ b/apps/renderer/src/modules/feed-column/list.desktop.tsx @@ -25,7 +25,7 @@ import { useInboxesGroupedData, useListsGroupedData, } from "./list.shared" -import { SortableFeedList, SortByAlphabeticalInbox, SortByAlphabeticalList } from "./sort-by" +import { SortableFeedList } from "./sort-by" const FeedListImpl = forwardRef( ({ className, view }, ref) => { @@ -214,23 +214,6 @@ const FeedListImpl = forwardRef - {hasListData && ( - <> -
- {t("words.lists")} -
- - - )} - {hasInboxData && ( - <> -
- {t("words.inbox")} -
- - - )} -
{(hasListData || hasInboxData) && ( diff --git a/apps/renderer/src/store/subscription/hooks.ts b/apps/renderer/src/store/subscription/hooks.ts index 03a3790de..2a469d1fb 100644 --- a/apps/renderer/src/store/subscription/hooks.ts +++ b/apps/renderer/src/store/subscription/hooks.ts @@ -14,7 +14,6 @@ import { subscriptionCategoryExistSelector, subscriptionsByFeedIsdSelector, } from "./selector" -import type { SubscriptionFlatModel } from "./store" import { useSubscriptionStore } from "./store" type FeedId = string @@ -88,13 +87,14 @@ export const useAllFeeds = () => { (store) => { const feedInfo = [] as { title: string; id: string }[] - const allSubscriptions = Object.values(store.feedIdByView).flat() + const allSubscriptions = Object.values(store.data).filter( + (subscription) => !subscription.listId && !subscription.inboxId, + ) - for (const feedId of allSubscriptions) { - const subscription = store.data[feedId]! - const feed = feedTitleMap[feedId] + for (const subscription of allSubscriptions) { + const feed = feedTitleMap[subscription.feedId] if (feed) { - feedInfo.push({ title: subscription.title || feed || "", id: feedId }) + feedInfo.push({ title: subscription.title || feed || "", id: subscription.feedId }) } } return feedInfo @@ -106,36 +106,18 @@ export const useAllFeeds = () => { export const useAllLists = () => { return useSubscriptionStore( - useCallback((store) => { - const lists = [] as SubscriptionFlatModel[] - - const allSubscriptions = Object.values(store.feedIdByView).flat() - - for (const feedId of allSubscriptions) { - const subscription = store.data[feedId]! - if (subscription.listId) { - lists.push(subscription) - } - } - return lists - }, []), + useCallback( + (store) => Object.values(store.data).filter((subscription) => subscription.listId), + [], + ), ) } export const useAllInboxes = () => { return useSubscriptionStore( - useCallback((store) => { - const inboxes = [] as SubscriptionFlatModel[] - - const allSubscriptions = Object.values(store.feedIdByView).flat() - - for (const feedId of allSubscriptions) { - const subscription = store.data[feedId]! - if (subscription.inboxId) { - inboxes.push(subscription) - } - } - return inboxes - }, []), + useCallback( + (store) => Object.values(store.data).filter((subscription) => subscription.inboxId), + [], + ), ) } diff --git a/apps/renderer/src/store/subscription/selector.ts b/apps/renderer/src/store/subscription/selector.ts index b735d9e01..4bbb62786 100644 --- a/apps/renderer/src/store/subscription/selector.ts +++ b/apps/renderer/src/store/subscription/selector.ts @@ -1,4 +1,4 @@ -import { FeedViewType } from "@follow/constants" +import type { FeedViewType } from "@follow/constants" import { FEED_COLLECTION_LIST, ROUTE_FEED_IN_FOLDER } from "~/constants" @@ -10,10 +10,7 @@ export const subscriptionCategoryExistSelector = (name: string) => (state: State state.categories.has(name) export const feedSubscriptionCountSelector = (state: State) => - Object.values(state.data).filter( - // FIXME: Backend data compatibility - (s) => !!s.feedId && !s.listId && !s.inboxId && state.subscriptionIdSet.has(s.feedId), - ).length + state.listIds.size + state.inboxIds.size + Object.values(state.feedIdByView).flat().length export const feedIdByViewSelector = (view: FeedViewType) => (state: State) => state.feedIdByView[view] @@ -54,11 +51,6 @@ export const folderFeedsByFeedIdSelector = return feedIds } -export const listSubscriptionCountSelector = (state: State) => - Object.values(state.data).filter((s) => !!s.listId && state.subscriptionIdSet.has(s.listId)) - .length +export const listSubscriptionCountSelector = (state: State) => state.listIds.size -export const inboxSubscriptionCountSelector = (state: State) => - Object.values(state.data).filter( - (s) => !!s.inboxId && state.feedIdByView[FeedViewType.Articles].includes(s.inboxId), - ).length +export const inboxSubscriptionCountSelector = (state: State) => state.inboxIds.size diff --git a/apps/renderer/src/store/subscription/store.ts b/apps/renderer/src/store/subscription/store.ts index 46ac3ad30..c811dc1fb 100644 --- a/apps/renderer/src/store/subscription/store.ts +++ b/apps/renderer/src/store/subscription/store.ts @@ -52,9 +52,13 @@ interface SubscriptionState { */ categories: Set /** - * All subscription ids set + * All list ids set */ - subscriptionIdSet: Set + listIds: Set + /** + * All inbox ids set + */ + inboxIds: Set } function morphResponseData(data: SubscriptionModel[]): SubscriptionFlatModel[] { @@ -102,7 +106,8 @@ export const useSubscriptionStore = createZustandStore("subsc feedIdByView: { ...emptyDataIdByView }, categoryOpenStateByView: { ...emptyCategoryOpenStateByView }, categories: new Set(), - subscriptionIdSet: new Set(), + listIds: new Set(), + inboxIds: new Set(), })) const set = useSubscriptionStore.setState @@ -118,18 +123,6 @@ class SubscriptionActions { constructor() { if (subscribeOnce) return subscribeOnce = true - // autorun - useSubscriptionStore.subscribe((next, prev) => { - if (next.feedIdByView !== prev.feedIdByView) { - const allSubscriptionIds = Object.values(next.feedIdByView).flat() - set((state) => { - return { - ...state, - subscriptionIdSet: new Set(allSubscriptionIds), - } - }) - } - }) useSubscriptionStore.subscribe((state, prev) => { if (state.data === prev.data) return @@ -199,12 +192,18 @@ class SubscriptionActions { }) immerSet((state) => { subscriptions.forEach((subscription) => { + if (subscription.listId) { + state.listIds.add(subscription.listId) + } else if (subscription.inboxId) { + state.inboxIds.add(subscription.inboxId) + } else { + state.feedIdByView[subscription.view].push(subscription.feedId) + } state.data[subscription.feedId] = omit(subscription, [ "feeds", "lists", "inboxes", ]) as SubscriptionFlatModel - state.feedIdByView[subscription.view].push(subscription.feedId) }) }) } @@ -398,6 +397,7 @@ class SubscriptionActions { await tx.run() } + // TODO async unfollow(feedIds: string[]) { // const feed = getFeedById(feedId) const feeds = feedIds.map((feedId) => getFeedById(feedId)) @@ -422,15 +422,21 @@ class SubscriptionActions { delete draft.data[feedId] - for (const view in draft.feedIdByView) { - const currentViewFeedIds = draft.feedIdByView[view] as string[] + if (subscription.listId) { + draft.listIds.delete(subscription.listId) + } else if (subscription.inboxId) { + draft.inboxIds.delete(subscription.inboxId) + } else { + for (const view in draft.feedIdByView) { + const currentViewFeedIds = draft.feedIdByView[view] as string[] - const idx = currentViewFeedIds.indexOf(feedId) + const idx = currentViewFeedIds.indexOf(feedId) - if (idx !== -1) { - currentViewFeedIds.splice(idx, 1) - ctx.viewDeleted[feedId] = ctx.viewDeleted[feedId] || [] - ctx.viewDeleted[feedId].push(Number.parseInt(view)) + if (idx !== -1) { + currentViewFeedIds.splice(idx, 1) + ctx.viewDeleted[feedId] = ctx.viewDeleted[feedId] || [] + ctx.viewDeleted[feedId].push(Number.parseInt(view)) + } } } }