feat: support configurable trust score threshold per context

This commit is contained in:
codytseng 2026-01-14 23:20:28 +08:00
parent 28a1b3096a
commit ca9610b711
46 changed files with 350 additions and 122 deletions

View file

@ -2,12 +2,20 @@ import NormalFeed from '@/components/NormalFeed'
import { checkAlgoRelay } from '@/lib/relay'
import { useFeed } from '@/providers/FeedProvider'
import relayInfoService from '@/services/relay-info.service'
import { useEffect, useState } from 'react'
import { useEffect, useMemo, useState } from 'react'
export default function RelaysFeed() {
const { relayUrls } = useFeed()
const { relayUrls, feedInfo } = useFeed()
const [isReady, setIsReady] = useState(false)
const [areAlgoRelays, setAreAlgoRelays] = useState(false)
const trustScoreFilterId = useMemo(() => {
if (feedInfo?.feedType === 'relay' && feedInfo.id) {
return `relay-${feedInfo.id}`
} else if (feedInfo?.feedType === 'relays' && feedInfo.id) {
return `relays-${feedInfo.id}`
}
return 'relays-default'
}, [feedInfo])
useEffect(() => {
const init = async () => {
@ -24,6 +32,7 @@ export default function RelaysFeed() {
return (
<NormalFeed
trustScoreFilterId={trustScoreFilterId}
subRequests={[{ urls: relayUrls, filter: {} }]}
areAlgoRelays={areAlgoRelays}
isMainFeed

View file

@ -1,5 +1,6 @@
import NotificationList from '@/components/NotificationList'
import TrustScoreFilter from '@/components/TrustScoreFilter'
import { SPECIAL_TRUST_SCORE_FILTER_ID } from '@/constants'
import PrimaryPageLayout from '@/layouts/PrimaryPageLayout'
import { usePrimaryPage } from '@/PageManager'
import { TPageRef } from '@/types'
@ -42,7 +43,7 @@ function NotificationListPageTitlebar() {
<Bell />
<div className="text-lg font-semibold">{t('Notifications')}</div>
</div>
<TrustScoreFilter />
<TrustScoreFilter filterId={SPECIAL_TRUST_SCORE_FILTER_ID.NOTIFICATIONS} />
</div>
)
}

View file

@ -4,6 +4,7 @@ import ProfileList from '@/components/ProfileList'
import { Skeleton } from '@/components/ui/skeleton'
import { useFetchEvent } from '@/hooks/useFetchEvent'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { getEventKey } from '@/lib/event'
import { getFollowPackInfoFromEvent } from '@/lib/event-metadata'
import { cn } from '@/lib/utils'
import { useNostr } from '@/providers/NostrProvider'
@ -96,7 +97,9 @@ const FollowPackPage = forwardRef(({ id, index }: { id?: string; index?: number
{/* Content */}
{tab === 'users' && <ProfileList pubkeys={pubkeys} />}
{tab === 'feed' && pubkeys.length > 0 && <Feed pubkeys={pubkeys} />}
{tab === 'feed' && pubkeys.length > 0 && (
<Feed trustScoreFilterId={`follow-pack-${getEventKey(event)}`} pubkeys={pubkeys} />
)}
</div>
</SecondaryPageLayout>
)
@ -104,7 +107,7 @@ const FollowPackPage = forwardRef(({ id, index }: { id?: string; index?: number
FollowPackPage.displayName = 'FollowPackPage'
export default FollowPackPage
function Feed({ pubkeys }: { pubkeys: string[] }) {
function Feed({ trustScoreFilterId, pubkeys }: { trustScoreFilterId: string; pubkeys: string[] }) {
const { pubkey: myPubkey } = useNostr()
const [subRequests, setSubRequests] = useState<TFeedSubRequest[]>([])
@ -112,5 +115,5 @@ function Feed({ pubkeys }: { pubkeys: string[] }) {
client.generateSubRequestsForPubkeys(pubkeys, myPubkey).then(setSubRequests)
}, [pubkeys, myPubkey])
return <NormalFeed subRequests={subRequests} />
return <NormalFeed trustScoreFilterId={trustScoreFilterId} subRequests={subRequests} />
}

View file

@ -0,0 +1,29 @@
import { Label } from '@/components/ui/label'
import { Slider } from '@/components/ui/slider'
import { SPECIAL_TRUST_SCORE_FILTER_ID } from '@/constants'
import { useUserTrust } from '@/providers/UserTrustProvider'
import { useTranslation } from 'react-i18next'
import SettingItem from './SettingItem'
export default function DefaultTrustScoreFilter() {
const { t } = useTranslation()
const { minTrustScore, updateMinTrustScore } = useUserTrust()
return (
<SettingItem className="flex-col items-start gap-2">
<Label className="text-base font-normal">
{t('Default trust score filter threshold ({{n}}%)', { n: minTrustScore })}
</Label>
<Slider
value={[minTrustScore]}
onValueChange={([value]) =>
updateMinTrustScore(SPECIAL_TRUST_SCORE_FILTER_ID.DEFAULT, value)
}
min={0}
max={100}
step={5}
className="w-full"
/>
</SettingItem>
)
}

View file

@ -19,6 +19,7 @@ import { SelectValue } from '@radix-ui/react-select'
import { RotateCcw } from 'lucide-react'
import { forwardRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import DefaultTrustScoreFilter from './DefaultTrustScoreFilter'
import MutedWords from './MutedWords'
import SettingItem from './SettingItem'
@ -150,6 +151,7 @@ const GeneralSettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
</SelectContent>
</Select>
</SettingItem>
<DefaultTrustScoreFilter />
<SettingItem>
<Label htmlFor="quick-reaction" className="text-base font-normal">
<div>{t('Quick reaction')}</div>

View file

@ -108,7 +108,22 @@ const NoteListPage = forwardRef(({ index }: { index?: number }, ref) => {
</div>
)
} else if (data) {
content = <NormalFeed subRequests={subRequests} disable24hMode={data.type !== 'domain'} />
let trustScoreFilterId: string
if (data.type === 'hashtag') {
trustScoreFilterId = 'hashtag'
} else if (data.type === 'domain') {
trustScoreFilterId = `domain-${data.domain}`
} else {
trustScoreFilterId = 'search'
}
content = (
<NormalFeed
trustScoreFilterId={trustScoreFilterId}
subRequests={subRequests}
disable24hMode={data.type !== 'domain'}
/>
)
}
return (