Skip to content

Commit

Permalink
feat(mobile): load archive entries (#2725)
Browse files Browse the repository at this point in the history
* feat(mobile): load archive entries

* only hydrate for view

* leave note

* fix type
  • Loading branch information
hyoban authored Feb 12, 2025
1 parent 3b1db30 commit d8a796d
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 52 deletions.
23 changes: 9 additions & 14 deletions apps/mobile/src/modules/context-menu/entry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,24 +59,19 @@ export const EntryItemContextMenu = ({ id, children }: PropsWithChildren<{ id: s
key="Star"
onSelect={() => {
if (isEntryStarred) {
collectionSyncService.unstarEntry({
createdAt: new Date().toISOString(),
collectionSyncService.unstarEntry(id)
toast.info("Unstarred")
} else {
if (!entry.feedId) {
toast.error("Feed not found")
return
}
collectionSyncService.starEntry({
feedId: entry.feedId,
entryId: id,
// TODO update view
view: 0,
})
toast.info("Unstarred")
} else {
collectionSyncService.starEntry(
{
createdAt: new Date().toISOString(),
feedId: entry.feedId,
entryId: id,
// TODO update view
view: 0,
},
0,
)
toast.info("Starred")
}
}}
Expand Down
24 changes: 22 additions & 2 deletions apps/mobile/src/modules/entry-list/action.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { Link } from "expo-router"
import { TouchableOpacity, View } from "react-native"
import { Text, TouchableOpacity, View } from "react-native"
import { useSafeAreaInsets } from "react-native-safe-area-context"

import { AddCuteReIcon } from "@/src/icons/add_cute_re"
import { LayoutLeftbarOpenCuteReIcon } from "@/src/icons/layout_leftbar_open_cute_re"
import { accentColor } from "@/src/theme/colors"

import { useFeedDrawer } from "../feed-drawer/atoms"
import {
setIsLoadingArchivedEntries,
useFeedDrawer,
useIsLoadingArchivedEntries,
} from "../feed-drawer/atoms"

const useActionPadding = () => {
const insets = useSafeAreaInsets()
Expand Down Expand Up @@ -42,3 +46,19 @@ export function HomeRightAction() {
</View>
)
}

export function LoadArchiveButton() {
const isLoadingArchivedEntries = useIsLoadingArchivedEntries()
if (isLoadingArchivedEntries) return null
return (
<View className="items-center pt-2">
<TouchableOpacity
onPress={() => {
setIsLoadingArchivedEntries(true)
}}
>
<Text className="text-label">Load archived entries</Text>
</TouchableOpacity>
</View>
)
}
13 changes: 10 additions & 3 deletions apps/mobile/src/modules/entry-list/entry-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { debouncedFetchEntryContentByStream } from "@/src/store/entry/store"

import { EntryItemContextMenu } from "../context-menu/entry"
import { ViewSelector } from "../feed-drawer/view-selector"
import { HomeLeftAction, HomeRightAction } from "./action"
import { HomeLeftAction, HomeRightAction, LoadArchiveButton } from "./action"
import { EntryListContentGrid } from "./entry-list-gird"

const headerHideableBottomHeight = 58
Expand Down Expand Up @@ -80,7 +80,7 @@ function EntryListContent({ entryIds }: { entryIds: string[] }) {
const scrollY = useContext(NavigationContext)?.scrollY

const { colorScheme } = useColorScheme()
const { fetchNextPage, isFetchingNextPage, refetch, isRefetching } = useFetchEntriesControls()
const { fetchNextPage, isFetching, refetch, isRefetching } = useFetchEntriesControls()

const onScroll = useCallback(
(e: NativeSyntheticEvent<NativeScrollEvent>) => {
Expand All @@ -95,6 +95,13 @@ function EntryListContent({ entryIds }: { entryIds: string[] }) {
)

const tabBarHeight = useBottomTabBarHeight()

const ListFooterComponent = useMemo(
() =>
isFetching ? <EntryItemSkeleton /> : screenType === "feed" ? <LoadArchiveButton /> : null,
[isFetching, screenType],
)

return (
<FlashList
refreshControl={
Expand Down Expand Up @@ -128,7 +135,7 @@ function EntryListContent({ entryIds }: { entryIds: string[] }) {
paddingBottom: tabBarHeight,
}}
ItemSeparatorComponent={ItemSeparator}
ListFooterComponent={isFetchingNextPage ? <EntryItemSkeleton /> : null}
ListFooterComponent={ListFooterComponent}
/>
)
}
Expand Down
24 changes: 23 additions & 1 deletion apps/mobile/src/modules/feed-drawer/atoms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,15 @@ const selectedTimelineAtom = atom<SelectedTimeline>({

const selectedFeedAtom = atom<SelectedFeed>(null)

const isLoadingArchivedEntriesAtom = atom(false)

export const useIsLoadingArchivedEntries = () => {
return useAtomValue(isLoadingArchivedEntriesAtom)
}
export const setIsLoadingArchivedEntries = (isLoading: boolean) => {
jotaiStore.set(isLoadingArchivedEntriesAtom, isLoading)
}

export const EntryListContext = createContext<{ type: "timeline" | "feed" }>({ type: "timeline" })
export const useEntryListContext = () => {
return useContext(EntryListContext)
Expand All @@ -129,6 +138,7 @@ export function useSelectedView() {

function getFetchEntryPayload(
selectedFeed: SelectedTimeline | SelectedFeed,
isArchived = false,
): FetchEntriesProps | null {
if (!selectedFeed) {
return null
Expand Down Expand Up @@ -158,6 +168,8 @@ function getFetchEntryPayload(
}
// No default
}

payload.isArchived = isArchived
return payload
}

Expand All @@ -167,17 +179,26 @@ export function useSelectedFeed() {
const selectedTimeline = useAtomValue(selectedTimelineAtom)
const selectedFeed = useAtomValue(selectedFeedAtom)

const isArchived = useIsLoadingArchivedEntries()
const payload = getFetchEntryPayload(
entryListContext.type === "feed" ? selectedFeed : selectedTimeline,
entryListContext.type === "feed" ? isArchived : false,
)
usePrefetchEntries(payload)

return entryListContext.type === "feed" ? selectedFeed : selectedTimeline
}

export function useFetchEntriesControls() {
const entryListContext = useEntryListContext()

const selectedFeed = useSelectedFeed()
const payload = getFetchEntryPayload(selectedFeed)
const isArchived = useIsLoadingArchivedEntries()

const payload = getFetchEntryPayload(
selectedFeed,
entryListContext.type === "feed" ? isArchived : false,
)
return usePrefetchEntries(payload)
}

Expand Down Expand Up @@ -220,6 +241,7 @@ export const selectTimeline = (state: SelectedTimeline) => {

export const selectFeed = (state: SelectedFeed) => {
jotaiStore.set(selectedFeedAtom, state)
jotaiStore.set(isLoadingArchivedEntriesAtom, false)
}

export const useViewDefinition = (view?: FeedViewType) => {
Expand Down
6 changes: 5 additions & 1 deletion apps/mobile/src/services/entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ class EntryServiceStatic implements Hydratable, Resetable {

async hydrate() {
const entries = await db.query.entriesTable.findMany()
entryActions.upsertManyInSession(entries.map((e) => dbStoreMorph.toEntryModel(e)))
// TODO: Find a way to determine whether entry is archived, and then only hydrate unarchived entries
entryActions.upsertManyInSession(
entries.map((e) => dbStoreMorph.toEntryModel(e)),
"view",
)
}
}

Expand Down
Loading

0 comments on commit d8a796d

Please sign in to comment.