feat(mobile): auto toggle readability for empty content

This commit is contained in:
Stephen Zhou 2025-05-07 09:57:06 +08:00
parent 59ec2443e9
commit a1a95216e7
No known key found for this signature in database
4 changed files with 34 additions and 30 deletions

View File

@ -20,7 +20,7 @@ import { isAndroid } from "@/src/lib/platform"
export const AISummary: FC<{
className?: string
summary: string
summary?: string
pending?: boolean
error?: string
onRetry?: () => void
@ -59,7 +59,7 @@ export const AISummary: FC<{
const purpleColor = useColor("purple")
if (pending) return null
if (pending || (!summary && !error)) return null
return (
<Animated.View
className={cn(
@ -105,7 +105,7 @@ export const AISummary: FC<{
readOnly
multiline
className="text-label text-[15px] leading-[22px]"
value={summary.trim()}
value={summary?.trim()}
/>
)}
</View>
@ -126,7 +126,7 @@ export const AISummary: FC<{
</View>
) : (
<Text className="text-label mt-2 text-[14px] leading-[22px]" selectable>
{summary.trim()}
{summary?.trim()}
</Text>
)}
</View>

View File

@ -26,6 +26,9 @@ export const EntryAISummary: FC<{
enabled: showAISummary,
},
)
const summaryToShow = showReadability
? summary?.readabilitySummary || summary?.summary
: summary?.summary
const status = useSummaryStore((state) => state.generatingStatus[entryId])
if (!showAISummary) return null
@ -33,11 +36,7 @@ export const EntryAISummary: FC<{
return (
<AISummary
className="my-3"
summary={
showReadability
? summary?.readabilitySummary || summary?.summary || ""
: summary?.summary || ""
}
summary={summaryToShow}
pending={status === SummaryGeneratingStatus.Pending}
error={status === SummaryGeneratingStatus.Error ? "Failed to generate summary" : undefined}
/>

View File

@ -1,6 +1,6 @@
import { FeedViewType } from "@follow/constants"
import { PortalProvider } from "@gorhom/portal"
import { atom, useAtomValue } from "jotai"
import { atom, useAtomValue, useSetAtom } from "jotai"
import { useEffect, useMemo } from "react"
import { Text, View } from "react-native"
import { useSafeAreaInsets } from "react-native-safe-area-context"
@ -33,7 +33,6 @@ export const EntryDetailScreen: NavigationControllerView<{
entryId: string
view: FeedViewType
}> = ({ entryId, view: viewType }) => {
usePrefetchEntryDetail(entryId)
useAutoMarkAsRead(entryId)
const entry = useEntry(entryId)
const translation = useEntryTranslation(entryId)
@ -57,12 +56,6 @@ export const EntryDetailScreen: NavigationControllerView<{
[entry?.settings?.readability, entry?.settings?.summary, entry?.settings?.translation],
)
useEffect(() => {
if (entry?.settings?.readability) {
entrySyncServices.fetchEntryReadabilityContent(entryId)
}
}, [entry?.settings?.readability, entryId])
return (
<EntryContentContext.Provider value={ctxValue}>
<PortalProvider>
@ -78,15 +71,15 @@ export const EntryDetailScreen: NavigationControllerView<{
className="relative rounded-xl py-4"
>
{viewType === FeedViewType.SocialMedia ? (
<EntrySocialTitle entryId={entryId as string} />
<EntrySocialTitle entryId={entryId} />
) : (
<>
<EntryTitle title={entry?.title || ""} entryId={entryId as string} />
<EntryInfo entryId={entryId as string} />
<EntryTitle title={entry?.title || ""} entryId={entryId} />
<EntryInfo entryId={entryId} />
</>
)}
</ItemPressable>
<EntryAISummary entryId={entryId as string} />
<EntryAISummary entryId={entryId} />
{entryWithTranslation && (
<View className="mt-3">
<EntryContentWebViewWithContext entry={entryWithTranslation} />
@ -94,7 +87,7 @@ export const EntryDetailScreen: NavigationControllerView<{
)}
{viewType === FeedViewType.SocialMedia && (
<View className="mt-2">
<EntryInfoSocial entryId={entryId as string} />
<EntryInfoSocial entryId={entryId} />
</View>
)}
</SafeNavigationScrollView>
@ -109,11 +102,28 @@ const EntryContentWebViewWithContext = ({ entry }: { entry: EntryWithTranslation
const showReadability = useAtomValue(showReadabilityAtom)
const translationSetting = useGeneralSettingKey("translation")
const showTranslation = useAtomValue(showAITranslationAtom)
const entryId = entry.id
usePrefetchEntryTranslation({
entryIds: [entry.id],
entryIds: [entryId],
withContent: true,
target: showReadability && entry.readabilityContent ? "readabilityContent" : "content",
})
// Auto toggle readability when content is empty
const setShowReadability = useSetAtom(showReadabilityAtom)
const { isPending } = usePrefetchEntryDetail(entryId)
useEffect(() => {
if (!isPending && !entry.content) {
setShowReadability(true)
}
}, [isPending, entry.content, setShowReadability])
useEffect(() => {
if (showReadability) {
entrySyncServices.fetchEntryReadabilityContent(entryId)
}
}, [showReadability, entryId])
return (
<EntryContentWebView
entry={entry}

View File

@ -122,17 +122,12 @@ class SummarySyncService {
})
.then((summary) => {
immerSet((state) => {
if (!summary.data) {
state.generatingStatus[entryId] = SummaryGeneratingStatus.Error
return ""
}
state.data[entryId] = {
lang: actionLanguage,
summary: target === "content" ? summary.data : state.data[entryId]?.summary || "",
summary: target === "content" ? summary.data || "" : state.data[entryId]?.summary || "",
readabilitySummary:
target === "readabilityContent"
? summary.data
? summary.data || ""
: state.data[entryId]?.readabilitySummary || null,
lastAccessed: Date.now(),
}