Skip to content

Commit

Permalink
feat: Remember the open state of the category, Ensure that each View'…
Browse files Browse the repository at this point in the history
…s category is independent
  • Loading branch information
Przeblysk committed Sep 29, 2024
1 parent a060986 commit 426bc7d
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 30 deletions.
39 changes: 21 additions & 18 deletions apps/renderer/src/modules/feed-column/category.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ type FeedId = string
interface FeedCategoryProps {
data: FeedId[]
view?: number
expansion: boolean
categoryOpenStateData: Record<string, boolean>
}

function FeedCategoryImpl({ data: ids, view, expansion }: FeedCategoryProps) {
function FeedCategoryImpl({ data: ids, view, categoryOpenStateData }: FeedCategoryProps) {
const { t } = useTranslation()

const sortByUnreadFeedList = useFeedUnreadStore((state) =>
Expand All @@ -46,17 +46,29 @@ function FeedCategoryImpl({ data: ids, view, expansion }: FeedCategoryProps) {
const folderName = subscription?.category || subscription.defaultCategory

const showCollapse = sortByUnreadFeedList.length > 1 || subscription?.category
const [open, setOpen] = useState(!showCollapse)
const open = folderName ? categoryOpenStateData[folderName] : true

const shouldOpen = useRouteParamsSelector(
(s) => typeof s.feedId === "string" && ids.includes(s.feedId),
)
const shouldOpen =
useRouteParamsSelector((s) => typeof s.feedId === "string" && ids.includes(s.feedId)) ||
ids.length === 1

const itemsRef = useRef<HTMLDivElement>(null)

const changeCategoryOpenState = (e) => {
e.stopPropagation()
if (!isCategoryEditing) {
setCategoryActive()
}
if (view !== undefined && folderName) {
subscriptionActions.changeCategoryOpenState(view, folderName)
}
}

useEffect(() => {
if (shouldOpen) {
setOpen(true)
if (!open && view !== undefined && folderName) {
subscriptionActions.changeCategoryOpenState(view, folderName)
}

const $items = itemsRef.current

Expand All @@ -66,12 +78,7 @@ function FeedCategoryImpl({ data: ids, view, expansion }: FeedCategoryProps) {
behavior: "smooth",
})
}
}, [shouldOpen])
useEffect(() => {
if (showCollapse) {
setOpen(expansion)
}
}, [expansion])
}, [shouldOpen, open, view, folderName])

const setCategoryActive = () => {
if (view !== undefined) {
Expand Down Expand Up @@ -200,11 +207,7 @@ function FeedCategoryImpl({ data: ids, view, expansion }: FeedCategoryProps) {
<div className="flex w-full min-w-0 items-center">
<button
type="button"
onClick={(e) => {
if (isCategoryEditing) return
e.stopPropagation()
setOpen(!open)
}}
onClick={changeCategoryOpenState}
data-state={open ? "open" : "close"}
className={cn(
"flex h-8 items-center [&_.i-mgc-right-cute-fi]:data-[state=open]:rotate-90",
Expand Down
54 changes: 42 additions & 12 deletions apps/renderer/src/modules/feed-column/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ import type { FeedViewType } from "~/lib/enum"
import { cn, sortByAlphabet } from "~/lib/utils"
import { Queries } from "~/queries"
import { getPreferredTitle, useFeedStore } from "~/store/feed"
import { getSubscriptionByFeedId, useSubscriptionByView } from "~/store/subscription"
import {
getSubscriptionByFeedId,
subscriptionActions,
useCategoryOpenStateByView,
useSubscriptionByView,
} from "~/store/subscription"
import { useFeedUnreadStore } from "~/store/unread"

import {
Expand Down Expand Up @@ -79,10 +84,10 @@ const useUpdateUnreadCount = () => {
}

function FeedListImpl({ className, view }: { className?: string; view: number }) {
const [expansion, setExpansion] = useState(false)
const feedsData = useFeedsGroupedData(view)
const listsData = useListsGroupedData(view)

const categoryOpenStateData = useCategoryOpenStateByView(view)
const expansion = Object.values(categoryOpenStateData).every((value) => value === true)
useUpdateUnreadCount()

const totalUnread = useFeedUnreadStore((state) => {
Expand Down Expand Up @@ -124,9 +129,15 @@ function FeedListImpl({ className, view }: { className?: string; view: number })
<div className="ml-2 flex items-center gap-3 text-sm text-theme-vibrancyFg">
<SortButton />
{expansion ? (
<i className="i-mgc-list-collapse-cute-re" onClick={() => setExpansion(false)} />
<i
className="i-mgc-list-collapse-cute-re"
onClick={() => subscriptionActions.expandCategoryOpenStateByView(view, false)}
/>
) : (
<i className="i-mgc-list-expansion-cute-re" onClick={() => setExpansion(true)} />
<i
className="i-mgc-list-expansion-cute-re"
onClick={() => subscriptionActions.expandCategoryOpenStateByView(view, true)}
/>
)}
<UnreadNumber unread={totalUnread} className="text-xs !text-inherit" />
</div>
Expand Down Expand Up @@ -157,7 +168,12 @@ function FeedListImpl({ className, view }: { className?: string; view: number })
<div className="mt-1 flex h-6 w-full shrink-0 items-center rounded-md px-2.5 text-xs font-semibold text-theme-vibrancyFg transition-colors">
{t("words.lists")}
</div>
<SortableList view={view} expansion={expansion} data={listsData} by="alphabetical" />
<SortableList
view={view}
data={listsData}
categoryOpenStateData={categoryOpenStateData}
by="alphabetical"
/>
</>
)}
<div
Expand All @@ -169,7 +185,11 @@ function FeedListImpl({ className, view }: { className?: string; view: number })
{t("words.feeds")}
</div>
{hasData ? (
<SortableList view={view} expansion={expansion} data={feedsData} />
<SortableList
view={view}
data={feedsData}
categoryOpenStateData={categoryOpenStateData}
/>
) : (
<div className="flex h-full flex-1 items-center font-normal text-zinc-500">
<Link
Expand Down Expand Up @@ -279,10 +299,10 @@ const SortButton = () => {

type FeedListProps = {
view: number
expansion: boolean
data: Record<string, string[]>
categoryOpenStateData: Record<string, boolean>
}
const SortByUnreadList = ({ view, expansion, data }: FeedListProps) => {
const SortByUnreadList = ({ view, data, categoryOpenStateData }: FeedListProps) => {
const isDesc = useFeedListSortSelector((s) => s.order === "desc")

const sortedByUnread = useFeedUnreadStore((state) => {
Expand All @@ -309,13 +329,18 @@ const SortByUnreadList = ({ view, expansion, data }: FeedListProps) => {
return (
<Fragment>
{sortedByUnread?.map(([category, ids]) => (
<FeedCategory key={category} data={ids} view={view} expansion={expansion} />
<FeedCategory
key={category}
data={ids}
view={view}
categoryOpenStateData={categoryOpenStateData}
/>
))}
</Fragment>
)
}

const SortByAlphabeticalList = ({ view, expansion, data }: FeedListProps) => {
const SortByAlphabeticalList = ({ view, data, categoryOpenStateData }: FeedListProps) => {
const categoryName2RealDisplayNameMap = useFeedStore((state) => {
const map = {} as Record<string, string>
for (const categoryName in data) {
Expand Down Expand Up @@ -353,7 +378,12 @@ const SortByAlphabeticalList = ({ view, expansion, data }: FeedListProps) => {
return (
<Fragment>
{sortedByAlphabetical.map((category) => (
<FeedCategory key={category} data={data[category]} view={view} expansion={expansion} />
<FeedCategory
key={category}
data={data[category]}
view={view}
categoryOpenStateData={categoryOpenStateData}
/>
))}
</Fragment>
)
Expand Down
4 changes: 4 additions & 0 deletions apps/renderer/src/store/subscription/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import { useSubscriptionStore } from "../subscription"
type FeedId = string
export const useFeedIdByView = (view: FeedViewType) =>
useSubscriptionStore((state) => state.feedIdByView[view] || [])

export const useCategoryOpenStateByView = (view: FeedViewType) =>
useSubscriptionStore((state) => state.categoryOpenStateByView[view])

export const useSubscriptionByView = (view: FeedViewType) =>
useSubscriptionStore((state) => state.feedIdByView[view].map((id) => state.data[id]))

Expand Down
50 changes: 50 additions & 0 deletions apps/renderer/src/store/subscription/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ interface SubscriptionState {
* Value: FeedId[]
*/
feedIdByView: Record<FeedViewType, FeedId[]>
/**
* Key: FeedViewType
* Value: Record<string, boolean>
*/
categoryOpenStateByView: Record<FeedViewType, Record<string, boolean>>
}

function morphResponseData(data: SubscriptionModel[]): SubscriptionFlatModel[] {
Expand Down Expand Up @@ -64,10 +69,19 @@ const emptyDataIdByView: Record<FeedViewType, FeedId[]> = {
[FeedViewType.SocialMedia]: [],
[FeedViewType.Videos]: [],
}
const emptyCategoryOpenStateByView: Record<FeedViewType, Record<string, boolean>> = {
[FeedViewType.Articles]: {},
[FeedViewType.Audios]: {},
[FeedViewType.Notifications]: {},
[FeedViewType.Pictures]: {},
[FeedViewType.SocialMedia]: {},
[FeedViewType.Videos]: {},
}

export const useSubscriptionStore = createZustandStore<SubscriptionState>("subscription")(() => ({
data: {},
feedIdByView: { ...emptyDataIdByView },
categoryOpenStateByView: { ...emptyCategoryOpenStateByView },
}))

const set = useSubscriptionStore.setState
Expand All @@ -91,16 +105,20 @@ class SubscriptionActions {
set((state) => ({
...state,
feedIdByView: { ...state.feedIdByView, [view]: [] },
categoryOpenStateByView: { ...state.categoryOpenStateByView },
}))
} else {
set((state) => ({
...state,
feedIdByView: { ...emptyDataIdByView },
categoryOpenStateByView: { ...state.categoryOpenStateByView },
}))
}

const transformedData = morphResponseData(res.data)

this.upsertMany(transformedData)
this.updateCategoryOpenState(transformedData.filter((s) => s.category || s.defaultCategory))
feedActions.upsertMany(res.data.map((s) => ("feeds" in s ? s.feeds : s.lists)))

return res.data
Expand All @@ -115,13 +133,44 @@ class SubscriptionActions {
subscriptions.forEach((subscription) => {
state.data[subscription.feedId] = omit(subscription, "feeds")
state.feedIdByView[subscription.view].push(subscription.feedId)
return state
})
}),
)
}

updateCategoryOpenState(subscriptions: SubscriptionFlatModel[]) {
set((state) =>
produce(state, (state) => {
subscriptions.forEach((subscription) => {
const folderName = subscription.category || subscription.defaultCategory
state.categoryOpenStateByView[subscription.view][folderName] =
state.categoryOpenStateByView[subscription.view][folderName] || false
return state
})
}),
)
}

changeCategoryOpenState(view: FeedViewType, category: string) {
set((state) =>
produce(state, (state) => {
state.categoryOpenStateByView[view][category] =
!state.categoryOpenStateByView[view][category]
}),
)
}

expandCategoryOpenStateByView(view: FeedViewType, isOpen: boolean) {
set((state) =>
produce(state, (state) => {
for (const category in state.categoryOpenStateByView[view]) {
state.categoryOpenStateByView[view][category] = isOpen
}
}),
)
}

async markReadByView(view: FeedViewType, filter?: MarkReadFilter) {
doMutationAndTransaction(
() =>
Expand Down Expand Up @@ -195,6 +244,7 @@ class SubscriptionActions {
set({
data: {},
feedIdByView: { ...emptyDataIdByView },
categoryOpenStateByView: { ...emptyCategoryOpenStateByView },
})
}

Expand Down

0 comments on commit 426bc7d

Please sign in to comment.