diff --git a/src/renderer/src/hooks/biz/useSubscriptionActions.tsx b/src/renderer/src/hooks/biz/useSubscriptionActions.tsx index 30ac97baaa..f9068980aa 100644 --- a/src/renderer/src/hooks/biz/useSubscriptionActions.tsx +++ b/src/renderer/src/hooks/biz/useSubscriptionActions.tsx @@ -1,6 +1,6 @@ import { apiClient } from "@renderer/lib/api-fetch" import { Queries } from "@renderer/queries" -import type { SubscriptionPlainModel } from "@renderer/store/subscription" +import type { SubscriptionFlatModel } from "@renderer/store/subscription" import { subscriptionActions } from "@renderer/store/subscription" import { feedUnreadActions } from "@renderer/store/unread" import { useMutation } from "@tanstack/react-query" @@ -15,7 +15,7 @@ export const useDeleteSubscription = ({ onSuccess?: () => void }) => useMutation({ - mutationFn: async (subscription: SubscriptionPlainModel) => + mutationFn: async (subscription: SubscriptionFlatModel) => subscriptionActions.unfollow(subscription.feedId).then((feed) => { Queries.subscription.byView(subscription.view).invalidate() feedUnreadActions.updateByFeedId(subscription.feedId, 0) diff --git a/src/renderer/src/modules/feed-column/category.tsx b/src/renderer/src/modules/feed-column/category.tsx index 8541f2d764..e8aff938df 100644 --- a/src/renderer/src/modules/feed-column/category.tsx +++ b/src/renderer/src/modules/feed-column/category.tsx @@ -8,9 +8,7 @@ import { ROUTE_FEED_IN_FOLDER } from "@renderer/lib/constants" import { stopPropagation } from "@renderer/lib/dom" import { showNativeMenu } from "@renderer/lib/native-menu" import { cn } from "@renderer/lib/utils" -import { - useSubscriptionByFeedId, -} from "@renderer/store/subscription" +import { useSubscriptionByFeedId } from "@renderer/store/subscription" import { useFeedUnreadStore } from "@renderer/store/unread" import { AnimatePresence, m } from "framer-motion" import { memo, useEffect, useState } from "react" @@ -38,19 +36,19 @@ function FeedCategoryImpl({ ids.sort((a, b) => (state.data[b] || 0) - (state.data[a] || 0)), ) - const showCollapse = sortByUnreadFeedList.length > 1 - const [open, setOpen] = useState(!showCollapse) + const navigate = useNavigateEntry() + + const subscription = useSubscriptionByFeedId(ids[0]) + const folderName = subscription?.category || subscription.defaultCategory + const showCollapse = sortByUnreadFeedList.length > 1 || subscription?.category + const [open, setOpen] = useState(!showCollapse) useEffect(() => { if (showCollapse) { setOpen(expansion) } }, [expansion]) - const navigate = useNavigateEntry() - - const subscription = useSubscriptionByFeedId(ids[0]) - const folderName = subscription?.category const setCategoryActive = () => { if (view !== undefined) { navigate({ @@ -67,7 +65,8 @@ function FeedCategoryImpl({ ) const isActive = useRouteParamsSelector( - (routerParams) => routerParams.feedId === `${ROUTE_FEED_IN_FOLDER}${folderName}`, + (routerParams) => + routerParams.feedId === `${ROUTE_FEED_IN_FOLDER}${folderName}`, ) const { present } = useModalStack() diff --git a/src/renderer/src/modules/feed-column/list.tsx b/src/renderer/src/modules/feed-column/list.tsx index 02a0381af7..472f2d91cd 100644 --- a/src/renderer/src/modules/feed-column/list.tsx +++ b/src/renderer/src/modules/feed-column/list.tsx @@ -25,11 +25,12 @@ const useGroupedData = (view: FeedViewType) => { const groupFolder = {} as Record for (const subscription of data) { - if (subscription.category) { - if (!groupFolder[subscription.category]) { - groupFolder[subscription.category] = [] + const category = subscription.category || subscription.defaultCategory + if (category) { + if (!groupFolder[category]) { + groupFolder[category] = [] } - groupFolder[subscription.category].push(subscription.feedId) + groupFolder[category].push(subscription.feedId) } } diff --git a/src/renderer/src/services/subscription.ts b/src/renderer/src/services/subscription.ts index 424d0a36ef..a6023f977d 100644 --- a/src/renderer/src/services/subscription.ts +++ b/src/renderer/src/services/subscription.ts @@ -1,22 +1,22 @@ import { subscriptionModel } from "@renderer/database" -import type { SubscriptionPlainModel } from "@renderer/store/subscription" +import type { SubscriptionFlatModel } from "@renderer/store/subscription" import { BaseService } from "./base" -type SubscriptionModelWithId = SubscriptionPlainModel & { id: string } +type SubscriptionModelWithId = SubscriptionFlatModel & { id: string } class SubscriptionServiceStatic extends BaseService { constructor() { super(subscriptionModel.table) } - override async upsertMany(data: SubscriptionPlainModel[]) { + override async upsertMany(data: SubscriptionFlatModel[]) { this.table.bulkPut( data.map((d) => ({ ...d, id: this.uniqueId(d.userId, d.feedId) })), ) } - override upsert(data: SubscriptionPlainModel) { + override upsert(data: SubscriptionFlatModel) { return this.table.put({ ...data, id: this.uniqueId(data.userId, data.feedId), diff --git a/src/renderer/src/store/search/index.ts b/src/renderer/src/store/search/index.ts index 223557edc8..9581e19ea5 100644 --- a/src/renderer/src/store/search/index.ts +++ b/src/renderer/src/store/search/index.ts @@ -9,7 +9,7 @@ import { import type { IFuseOptions } from "fuse.js" import Fuse from "fuse.js" -import type { SubscriptionPlainModel } from "../subscription" +import type { SubscriptionFlatModel } from "../subscription" import { createZustandStore } from "../utils/helper" import { SearchType } from "./constants" import { defineSearchInstance } from "./helper" @@ -83,7 +83,7 @@ class SearchActions { } const processedSubscriptions = [] as SearchResult< - SubscriptionPlainModel, + SubscriptionFlatModel, { feedId: string } >[] for (const subscription of subscriptions) { diff --git a/src/renderer/src/store/search/types.ts b/src/renderer/src/store/search/types.ts index 93ff7b00ff..04fc4b63e0 100644 --- a/src/renderer/src/store/search/types.ts +++ b/src/renderer/src/store/search/types.ts @@ -1,6 +1,6 @@ import type { EntryModel, FeedModel } from "@renderer/models" -import type { SubscriptionPlainModel } from "../subscription" +import type { SubscriptionFlatModel } from "../subscription" import type { SearchType } from "./constants" // @ts-expect-error @@ -12,7 +12,7 @@ export interface SearchResult export interface SearchState { feeds: SearchResult[] entries: SearchResult[] - subscriptions: SearchResult[] + subscriptions: SearchResult[] keyword: string searchType: SearchType diff --git a/src/renderer/src/store/subscription/hooks.ts b/src/renderer/src/store/subscription/hooks.ts index 662a72f0f4..e4f845fbae 100644 --- a/src/renderer/src/store/subscription/hooks.ts +++ b/src/renderer/src/store/subscription/hooks.ts @@ -1,4 +1,7 @@ -import { FEED_COLLECTION_LIST, ROUTE_FEED_IN_FOLDER } from "@renderer/lib/constants" +import { + FEED_COLLECTION_LIST, + ROUTE_FEED_IN_FOLDER, +} from "@renderer/lib/constants" import type { FeedViewType } from "@renderer/lib/enum" import { useSubscriptionStore } from "../subscription" @@ -17,7 +20,9 @@ export const useSubscriptionByFeedId = (feedId: FeedId) => export const useFolderFeedsByFeedId = (feedId?: string) => useSubscriptionStore((state): string[] | null => { if (typeof feedId !== "string") return null - if (feedId === FEED_COLLECTION_LIST) { return [feedId] } + if (feedId === FEED_COLLECTION_LIST) { + return [feedId] + } if (!feedId.startsWith(ROUTE_FEED_IN_FOLDER)) { return null @@ -27,7 +32,7 @@ export const useFolderFeedsByFeedId = (feedId?: string) => const feedIds: string[] = [] for (const feedId in state.data) { const subscription = state.data[feedId] - if (subscription.category === folderName) { + if (subscription.category === folderName || subscription.defaultCategory === folderName) { feedIds.push(feedId) } } diff --git a/src/renderer/src/store/subscription/store.ts b/src/renderer/src/store/subscription/store.ts index 94ef41e706..1bfcb7dd64 100644 --- a/src/renderer/src/store/subscription/store.ts +++ b/src/renderer/src/store/subscription/store.ts @@ -13,13 +13,15 @@ import { feedActions, getFeedById } from "../feed" import { feedUnreadActions } from "../unread" import { createZustandStore, doMutationAndTransaction } from "../utils/helper" -export type SubscriptionPlainModel = Omit +export type SubscriptionFlatModel = Omit & { + defaultCategory?: string +} interface SubscriptionState { /** * Key: feedId * Value: SubscriptionPlainModel */ - data: Record + data: Record /** * Key: FeedViewType * Value: FeedId[] @@ -27,16 +29,22 @@ interface SubscriptionState { dataIdByView: Record } -function morphResponseData(data: SubscriptionModel[]) { +function morphResponseData(data: SubscriptionModel[]): SubscriptionFlatModel[] { + const result: SubscriptionFlatModel[] = [] for (const subscription of data) { + const cloned: SubscriptionFlatModel = { ...subscription } if (!subscription.category && subscription.feeds) { const { siteUrl } = subscription.feeds if (!siteUrl) continue const parsed = parse(siteUrl) - parsed.domain && - (subscription.category = capitalizeFirstLetter(parsed.domain)) + + if (parsed.domain) { + cloned.defaultCategory = capitalizeFirstLetter(parsed.domain) + } } + result.push(cloned) } + return result } const emptyDataIdByView: Record = { @@ -79,14 +87,14 @@ class SubscriptionActions { })) } - morphResponseData(res.data) - this.upsertMany(res.data) + const transformedData = morphResponseData(res.data) + this.upsertMany(transformedData) feedActions.upsertMany(res.data.map((s) => s.feeds)) return res.data } - upsertMany(subscriptions: SubscriptionPlainModel[]) { + upsertMany(subscriptions: SubscriptionFlatModel[]) { runTransactionInScope(() => { SubscriptionService.upsertMany(subscriptions) }) @@ -151,17 +159,20 @@ class SubscriptionActions { const { siteUrl } = feed if (!siteUrl) return const parsed = parse(siteUrl) + subscription.category = null // The logic for removing Category here is to use domain as the default category name. parsed.domain && - (subscription.category = capitalizeFirstLetter( - parsed.domain, + (subscription.defaultCategory = ( + capitalizeFirstLetter(parsed.domain) )) } }) }), ) const { data } = get() - return ids.map((id) => data[id] && SubscriptionService.upsert(data[id])) + return ids.map( + (id) => data[id] && SubscriptionService.upsert(data[id]), + ) }, { doTranscationWhenMutationFail: false,