feat: use insertedBefore for mark above read

This commit is contained in:
DIYgod 2025-07-05 11:59:43 +08:00
parent 3488390afc
commit a17db88b60
No known key found for this signature in database
10 changed files with 79 additions and 19 deletions

View File

@ -2,16 +2,34 @@ import { FeedViewType, views } from "@follow/constants"
import { FlatMarkAllReadButton } from "./mark-all-button"
export const FooterMarkItem = ({ view }: { view: FeedViewType }) => {
export const FooterMarkItem = ({
view,
fetchedTime,
}: {
view: FeedViewType
fetchedTime?: number
}) => {
const filter = fetchedTime
? {
insertedBefore: fetchedTime,
}
: undefined
if (view === FeedViewType.SocialMedia) {
return <SocialMediaFooterMarkItem />
return <SocialMediaFooterMarkItem filter={filter} />
} else if (views[view]!.gridMode) {
return <GridFooterMarkItem />
return <GridFooterMarkItem filter={filter} />
}
return <CommonFooterMarkItem />
return <CommonFooterMarkItem filter={filter} />
}
const SocialMediaFooterMarkItem = () => {
interface FooterMarkItemProps {
filter?: {
insertedBefore: number
}
}
const SocialMediaFooterMarkItem = ({ filter }: FooterMarkItemProps) => {
return (
<div className="relative flex w-full">
<FlatMarkAllReadButton
@ -19,30 +37,33 @@ const SocialMediaFooterMarkItem = () => {
buttonClassName="w-[645px] mx-auto mb-4 pl-7 py-4"
iconClassName="mr-1 text-lg"
which="above"
filter={filter}
/>
</div>
)
}
const GridFooterMarkItem = () => {
const GridFooterMarkItem = ({ filter }: FooterMarkItemProps) => {
return (
<div className="relative flex w-full">
<FlatMarkAllReadButton
buttonClassName="w-full py-4"
iconClassName="mr-1 text-base"
which="above"
filter={filter}
/>
</div>
)
}
const CommonFooterMarkItem = () => {
const CommonFooterMarkItem = ({ filter }: FooterMarkItemProps) => {
return (
<FlatMarkAllReadButton
className="justify-start"
buttonClassName="w-full rounded-none px-6 py-4"
iconClassName="mr-1 text-base"
which="above"
filter={filter}
/>
)
}

View File

@ -123,6 +123,7 @@ const useRemoteEntries = (): UseEntriesReturn => {
isFetching: query.isFetching,
hasNextPage: query.hasNextPage,
error: query.isError ? query.error : null,
fetchedTime,
}
}

View File

@ -4,10 +4,14 @@ import { unreadSyncService } from "@follow/store/unread/store"
import { getGeneralSettings } from "~/atoms/settings/general"
export interface MarkAllFilter {
startTime: number
endTime: number
}
export type MarkAllFilter =
| {
startTime: number
endTime: number
}
| {
insertedBefore: number
}
export const markAllByRoute = async (
data: {

View File

@ -165,7 +165,7 @@ function EntryColumnImpl() {
fetchNextPage={fetchNextPage}
refetch={entries.refetch}
groupCounts={groupedCounts}
Footer={<FooterMarkItem view={view} />}
Footer={<FooterMarkItem view={view} fetchedTime={entries.fetchedTime} />}
/>
)}
</EntryColumnWrapper>

View File

@ -1,4 +1,4 @@
import { and, between, eq, inArray, or } from "drizzle-orm"
import { and, between, eq, inArray, lt, or } from "drizzle-orm"
import { db } from "../db"
import { entriesTable } from "../schemas"
@ -11,6 +11,10 @@ interface PublishAtTimeRangeFilter {
endTime: number
}
interface InsertedBeforeTimeRangeFilter {
insertedBefore: number
}
class EntryServiceStatic implements Resetable {
async reset() {
await db.delete(entriesTable).execute()
@ -40,7 +44,7 @@ class EntryServiceStatic implements Resetable {
entry: Partial<EntrySchema>
entryIds?: string[]
feedIds?: string[]
time?: PublishAtTimeRangeFilter
time?: PublishAtTimeRangeFilter | InsertedBeforeTimeRangeFilter
}) {
if (!entryIds && !feedIds) return
await db
@ -49,9 +53,12 @@ class EntryServiceStatic implements Resetable {
.where(
and(
or(inArray(entriesTable.id, entryIds ?? []), inArray(entriesTable.feedId, feedIds ?? [])),
time
time && "startTime" in time
? between(entriesTable.publishedAt, new Date(time.startTime), new Date(time.endTime))
: undefined,
time && "insertedBefore" in time
? lt(entriesTable.insertedAt, new Date(time.insertedBefore))
: undefined,
),
)
}

View File

@ -19498,6 +19498,7 @@ declare const _routes: hono_hono_base.HonoBase<Env, ({
excludePrivate?: boolean | undefined;
startTime?: number | undefined;
endTime?: number | undefined;
insertedBefore?: number | undefined;
};
};
output: {

View File

@ -14,7 +14,11 @@ import { honoMorph } from "../morph/hono"
import { storeDbMorph } from "../morph/store-db"
import { getSubscriptionById } from "../subscription/getter"
import { getDefaultCategory } from "../subscription/utils"
import type { FeedIdOrInboxHandle, PublishAtTimeRangeFilter } from "../unread/types"
import type {
FeedIdOrInboxHandle,
InsertedBeforeTimeRangeFilter,
PublishAtTimeRangeFilter,
} from "../unread/types"
import { whoami } from "../user/getters"
import { userActions } from "../user/store"
import { getEntry } from "./getter"
@ -311,7 +315,7 @@ class EntryActions implements Hydratable, Resetable {
entryIds?: EntryId[]
ids?: FeedIdOrInboxHandle[]
read: boolean
time?: PublishAtTimeRangeFilter
time?: PublishAtTimeRangeFilter | InsertedBeforeTimeRangeFilter
}) {
const affectedEntryIds = new Set<EntryId>()
@ -325,11 +329,19 @@ class EntryActions implements Hydratable, Resetable {
if (
time &&
"startTime" in time &&
(+new Date(entry.publishedAt) < time.startTime ||
+new Date(entry.publishedAt) > time.endTime)
) {
continue
}
if (
time &&
"insertedBefore" in time &&
+new Date(entry.insertedAt) >= time.insertedBefore
) {
continue
}
if (entry.read !== read) {
entry.read = read
@ -351,11 +363,19 @@ class EntryActions implements Hydratable, Resetable {
for (const entry of entries) {
if (
time &&
"startTime" in time &&
(+new Date(entry.publishedAt) < time.startTime ||
+new Date(entry.publishedAt) > time.endTime)
) {
continue
}
if (
time &&
"insertedBefore" in time &&
+new Date(entry.insertedAt) >= time.insertedBefore
) {
continue
}
if (entry.read !== read) {
entry.read = read

View File

@ -38,6 +38,7 @@ export type UseEntriesReturn = {
isFetchingNextPage: boolean
hasNextPage: boolean
error: Error | null
fetchedTime?: number
}
export type UseEntriesControl = Pick<

View File

@ -13,6 +13,7 @@ import { getListFeedIds } from "../list/getters"
import { getSubscribedFeedIdAndInboxHandlesByView } from "../subscription/getter"
import type {
FeedIdOrInboxHandle,
InsertedBeforeTimeRangeFilter,
PublishAtTimeRangeFilter,
UnreadState,
UnreadStoreModel,
@ -43,7 +44,7 @@ class UnreadSyncService {
request,
}: {
ids: FeedIdOrInboxHandle[]
time?: PublishAtTimeRangeFilter
time?: PublishAtTimeRangeFilter | InsertedBeforeTimeRangeFilter
request: () => Promise<UnreadStoreModel>
}) {
if (!ids || ids.length === 0) return
@ -116,7 +117,7 @@ class UnreadSyncService {
feedIdList?: string[]
inboxId?: string
} | null
time?: PublishAtTimeRangeFilter
time?: PublishAtTimeRangeFilter | InsertedBeforeTimeRangeFilter
excludePrivate: boolean
}) {
const request = async () => {

View File

@ -3,6 +3,10 @@ export interface PublishAtTimeRangeFilter {
endTime: number
}
export interface InsertedBeforeTimeRangeFilter {
insertedBefore: number
}
export interface UnreadUpdateOptions {
reset?: boolean
}