feat: add NSFW display policy setting
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useSecondaryPage } from '@/PageManager'
|
||||
import { ExtendedKind, SUPPORTED_KINDS } from '@/constants'
|
||||
import { ExtendedKind, NSFW_DISPLAY_POLICY, SUPPORTED_KINDS } from '@/constants'
|
||||
import { getParentStuff, isNsfwEvent } from '@/lib/event'
|
||||
import { toExternalContent, toNote } from '@/lib/link'
|
||||
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
|
||||
@@ -55,10 +55,14 @@ export default function Note({
|
||||
const { parentEventId, parentExternalContent } = useMemo(() => {
|
||||
return getParentStuff(event)
|
||||
}, [event])
|
||||
const { defaultShowNsfw } = useContentPolicy()
|
||||
const { nsfwDisplayPolicy } = useContentPolicy()
|
||||
const [showNsfw, setShowNsfw] = useState(false)
|
||||
const { mutePubkeySet } = useMuteList()
|
||||
const [showMuted, setShowMuted] = useState(false)
|
||||
const isNsfw = useMemo(
|
||||
() => (nsfwDisplayPolicy === NSFW_DISPLAY_POLICY.SHOW ? false : isNsfwEvent(event)),
|
||||
[event, nsfwDisplayPolicy]
|
||||
)
|
||||
|
||||
let content: React.ReactNode
|
||||
if (
|
||||
@@ -72,7 +76,7 @@ export default function Note({
|
||||
content = <UnknownNote className="mt-2" event={event} />
|
||||
} else if (mutePubkeySet.has(event.pubkey) && !showMuted) {
|
||||
content = <MutedNote show={() => setShowMuted(true)} />
|
||||
} else if (!defaultShowNsfw && isNsfwEvent(event) && !showNsfw) {
|
||||
} else if (isNsfw && !showNsfw) {
|
||||
content = <NsfwNote show={() => setShowNsfw(true)} />
|
||||
} else if (event.kind === kinds.Highlights) {
|
||||
content = <Highlight className="mt-2" event={event} />
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Skeleton } from '@/components/ui/skeleton'
|
||||
import { isMentioningMutedUsers } from '@/lib/event'
|
||||
import { NSFW_DISPLAY_POLICY } from '@/constants'
|
||||
import { isMentioningMutedUsers, isNsfwEvent } from '@/lib/event'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
|
||||
import { useMuteList } from '@/providers/MuteListProvider'
|
||||
@@ -22,7 +23,7 @@ export default function NoteCard({
|
||||
reposters?: string[]
|
||||
}) {
|
||||
const { mutePubkeySet } = useMuteList()
|
||||
const { hideContentMentioningMutedUsers } = useContentPolicy()
|
||||
const { hideContentMentioningMutedUsers, nsfwDisplayPolicy } = useContentPolicy()
|
||||
const shouldHide = useMemo(() => {
|
||||
if (filterMutedNotes && mutePubkeySet.has(event.pubkey)) {
|
||||
return true
|
||||
@@ -30,8 +31,11 @@ export default function NoteCard({
|
||||
if (hideContentMentioningMutedUsers && isMentioningMutedUsers(event, mutePubkeySet)) {
|
||||
return true
|
||||
}
|
||||
if (nsfwDisplayPolicy === NSFW_DISPLAY_POLICY.HIDE && isNsfwEvent(event)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}, [event, filterMutedNotes, mutePubkeySet])
|
||||
}, [event, filterMutedNotes, mutePubkeySet, nsfwDisplayPolicy])
|
||||
if (shouldHide) return null
|
||||
|
||||
if (event.kind === kinds.Repost || event.kind === kinds.GenericRepost) {
|
||||
|
||||
@@ -28,7 +28,6 @@ export const StorageKey = {
|
||||
TRANSLATION_SERVICE_CONFIG_MAP: 'translationServiceConfigMap',
|
||||
MEDIA_UPLOAD_SERVICE_CONFIG_MAP: 'mediaUploadServiceConfigMap',
|
||||
HIDE_UNTRUSTED_NOTES: 'hideUntrustedNotes',
|
||||
DEFAULT_SHOW_NSFW: 'defaultShowNsfw',
|
||||
DISMISSED_TOO_MANY_RELAYS_ALERT: 'dismissedTooManyRelaysAlert',
|
||||
SHOW_KINDS: 'showKinds',
|
||||
SHOW_KINDS_VERSION: 'showKindsVersion',
|
||||
@@ -43,6 +42,8 @@ export const StorageKey = {
|
||||
FILTER_OUT_ONION_RELAYS: 'filterOutOnionRelays',
|
||||
QUICK_REACTION: 'quickReaction',
|
||||
QUICK_REACTION_EMOJI: 'quickReactionEmoji',
|
||||
NSFW_DISPLAY_POLICY: 'nsfwDisplayPolicy',
|
||||
DEFAULT_SHOW_NSFW: 'defaultShowNsfw', // deprecated
|
||||
PINNED_PUBKEYS: 'pinnedPubkeys', // deprecated
|
||||
MEDIA_UPLOAD_SERVICE: 'mediaUploadService', // deprecated
|
||||
HIDE_UNTRUSTED_EVENTS: 'hideUntrustedEvents', // deprecated
|
||||
@@ -170,6 +171,12 @@ export const MEDIA_AUTO_LOAD_POLICY = {
|
||||
NEVER: 'never'
|
||||
} as const
|
||||
|
||||
export const NSFW_DISPLAY_POLICY = {
|
||||
HIDE: 'hide',
|
||||
HIDE_CONTENT: 'hide_content',
|
||||
SHOW: 'show'
|
||||
} as const
|
||||
|
||||
export const MAX_PINNED_NOTES = 10
|
||||
|
||||
export const PRIMARY_COLORS = {
|
||||
|
||||
@@ -571,6 +571,11 @@ export default {
|
||||
'If enabled, you can react with a single click. Click and hold for more options':
|
||||
'إذا تم التمكين، يمكنك التفاعل بنقرة واحدة. اضغط مع الاستمرار للمزيد من الخيارات',
|
||||
'Quick reaction emoji': 'رمز تعبيري للرد السريع',
|
||||
'Select emoji': 'اختر رمز تعبيري'
|
||||
'Select emoji': 'اختر رمز تعبيري',
|
||||
'NSFW content display': 'NSFW content display',
|
||||
'Hide completely': 'Hide completely',
|
||||
'Show but hide content': 'Show but hide content',
|
||||
'Show directly': 'Show directly',
|
||||
'Click to view': 'Click to view'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -587,6 +587,11 @@ export default {
|
||||
'If enabled, you can react with a single click. Click and hold for more options':
|
||||
'Wenn aktiviert, können Sie mit einem Klick reagieren. Klicken und halten Sie für weitere Optionen',
|
||||
'Quick reaction emoji': 'Schnellreaktions-Emoji',
|
||||
'Select emoji': 'Emoji auswählen'
|
||||
'Select emoji': 'Emoji auswählen',
|
||||
'NSFW content display': 'NSFW content display',
|
||||
'Hide completely': 'Hide completely',
|
||||
'Show but hide content': 'Show but hide content',
|
||||
'Show directly': 'Show directly',
|
||||
'Click to view': 'Click to view'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,6 +574,11 @@ export default {
|
||||
'If enabled, you can react with a single click. Click and hold for more options':
|
||||
'If enabled, you can react with a single click. Click and hold for more options',
|
||||
'Quick reaction emoji': 'Quick reaction emoji',
|
||||
'Select emoji': 'Select emoji'
|
||||
'Select emoji': 'Select emoji',
|
||||
'NSFW content display': 'NSFW content display',
|
||||
'Hide completely': 'Hide completely',
|
||||
'Show but hide content': 'Show but hide content',
|
||||
'Show directly': 'Show directly',
|
||||
'Click to view': 'Click to view'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -583,6 +583,11 @@ export default {
|
||||
'If enabled, you can react with a single click. Click and hold for more options':
|
||||
'Si está habilitado, puedes reaccionar con un solo clic. Mantén presionado para más opciones',
|
||||
'Quick reaction emoji': 'Emoji de reacción rápida',
|
||||
'Select emoji': 'Seleccionar emoji'
|
||||
'Select emoji': 'Seleccionar emoji',
|
||||
'NSFW content display': 'NSFW content display',
|
||||
'Hide completely': 'Hide completely',
|
||||
'Show but hide content': 'Show but hide content',
|
||||
'Show directly': 'Show directly',
|
||||
'Click to view': 'Click to view'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -577,6 +577,11 @@ export default {
|
||||
'If enabled, you can react with a single click. Click and hold for more options':
|
||||
'اگر فعال باشد، میتوانید با یک کلیک واکنش نشان دهید. برای گزینههای بیشتر کلیک کنید و نگه دارید',
|
||||
'Quick reaction emoji': 'ایموجی واکنش سریع',
|
||||
'Select emoji': 'انتخاب ایموجی'
|
||||
'Select emoji': 'انتخاب ایموجی',
|
||||
'NSFW content display': 'NSFW content display',
|
||||
'Hide completely': 'Hide completely',
|
||||
'Show but hide content': 'Show but hide content',
|
||||
'Show directly': 'Show directly',
|
||||
'Click to view': 'Click to view'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -584,8 +584,13 @@ export default {
|
||||
notes: 'notes',
|
||||
'Quick reaction': 'Réaction rapide',
|
||||
'If enabled, you can react with a single click. Click and hold for more options':
|
||||
'Si activé, vous pouvez réagir en un seul clic. Maintenez enfoncé pour plus d\'options',
|
||||
"Si activé, vous pouvez réagir en un seul clic. Maintenez enfoncé pour plus d'options",
|
||||
'Quick reaction emoji': 'Emoji de réaction rapide',
|
||||
'Select emoji': 'Sélectionner un emoji'
|
||||
'Select emoji': 'Sélectionner un emoji',
|
||||
'NSFW content display': 'NSFW content display',
|
||||
'Hide completely': 'Hide completely',
|
||||
'Show but hide content': 'Show but hide content',
|
||||
'Show directly': 'Show directly',
|
||||
'Click to view': 'Click to view'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -578,6 +578,11 @@ export default {
|
||||
'If enabled, you can react with a single click. Click and hold for more options':
|
||||
'यदि सक्षम है, तो आप एक क्लिक से प्रतिक्रिया दे सकते हैं। अधिक विकल्पों के लिए क्लिक करें और रोकें',
|
||||
'Quick reaction emoji': 'त्वरित प्रतिक्रिया इमोजी',
|
||||
'Select emoji': 'इमोजी चुनें'
|
||||
'Select emoji': 'इमोजी चुनें',
|
||||
'NSFW content display': 'NSFW content display',
|
||||
'Hide completely': 'Hide completely',
|
||||
'Show but hide content': 'Show but hide content',
|
||||
'Show directly': 'Show directly',
|
||||
'Click to view': 'Click to view'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -572,6 +572,11 @@ export default {
|
||||
'If enabled, you can react with a single click. Click and hold for more options':
|
||||
'Ha engedélyezve van, egy kattintással reagálhat. Tartsa lenyomva további lehetőségekért',
|
||||
'Quick reaction emoji': 'Gyors reakció emoji',
|
||||
'Select emoji': 'Emoji kiválasztása'
|
||||
'Select emoji': 'Emoji kiválasztása',
|
||||
'NSFW content display': 'NSFW content display',
|
||||
'Hide completely': 'Hide completely',
|
||||
'Show but hide content': 'Show but hide content',
|
||||
'Show directly': 'Show directly',
|
||||
'Click to view': 'Click to view'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -582,6 +582,11 @@ export default {
|
||||
'If enabled, you can react with a single click. Click and hold for more options':
|
||||
'Se abilitato, puoi reagire con un solo clic. Fai clic e tieni premuto per altre opzioni',
|
||||
'Quick reaction emoji': 'Emoji reazione rapida',
|
||||
'Select emoji': 'Seleziona emoji'
|
||||
'Select emoji': 'Seleziona emoji',
|
||||
'NSFW content display': 'NSFW content display',
|
||||
'Hide completely': 'Hide completely',
|
||||
'Show but hide content': 'Show but hide content',
|
||||
'Show directly': 'Show directly',
|
||||
'Click to view': 'Click to view'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -577,6 +577,11 @@ export default {
|
||||
'If enabled, you can react with a single click. Click and hold for more options':
|
||||
'有効にすると、ワンクリックでリアクションできます。長押しで他のオプションを表示',
|
||||
'Quick reaction emoji': 'クイックリアクション絵文字',
|
||||
'Select emoji': '絵文字を選択'
|
||||
'Select emoji': '絵文字を選択',
|
||||
'NSFW content display': 'NSFWコンテンツの表示',
|
||||
'Hide completely': '完全に非表示',
|
||||
'Show but hide content': '表示するがコンテンツを非表示',
|
||||
'Show directly': '直接表示',
|
||||
'Click to view': 'クリックして表示'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -576,6 +576,11 @@ export default {
|
||||
'If enabled, you can react with a single click. Click and hold for more options':
|
||||
'활성화하면 한 번의 클릭으로 반응할 수 있습니다. 더 많은 옵션을 보려면 길게 누르세요',
|
||||
'Quick reaction emoji': '빠른 반응 이모지',
|
||||
'Select emoji': '이모지 선택'
|
||||
'Select emoji': '이모지 선택',
|
||||
'NSFW content display': 'NSFW content display',
|
||||
'Hide completely': 'Hide completely',
|
||||
'Show but hide content': 'Show but hide content',
|
||||
'Show directly': 'Show directly',
|
||||
'Click to view': 'Click to view'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -583,6 +583,11 @@ export default {
|
||||
'If enabled, you can react with a single click. Click and hold for more options':
|
||||
'Jeśli włączone, możesz zareagować jednym kliknięciem. Kliknij i przytrzymaj, aby uzyskać więcej opcji',
|
||||
'Quick reaction emoji': 'Emoji szybkiej reakcji',
|
||||
'Select emoji': 'Wybierz emoji'
|
||||
'Select emoji': 'Wybierz emoji',
|
||||
'NSFW content display': 'NSFW content display',
|
||||
'Hide completely': 'Hide completely',
|
||||
'Show but hide content': 'Show but hide content',
|
||||
'Show directly': 'Show directly',
|
||||
'Click to view': 'Click to view'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -578,6 +578,11 @@ export default {
|
||||
'If enabled, you can react with a single click. Click and hold for more options':
|
||||
'Se ativado, você pode reagir com um único clique. Clique e segure para mais opções',
|
||||
'Quick reaction emoji': 'Emoji de reação rápida',
|
||||
'Select emoji': 'Selecionar emoji'
|
||||
'Select emoji': 'Selecionar emoji',
|
||||
'NSFW content display': 'NSFW content display',
|
||||
'Hide completely': 'Hide completely',
|
||||
'Show but hide content': 'Show but hide content',
|
||||
'Show directly': 'Show directly',
|
||||
'Click to view': 'Click to view'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,6 +581,11 @@ export default {
|
||||
'If enabled, you can react with a single click. Click and hold for more options':
|
||||
'Se ativado, pode reagir com um único clique. Clique e mantenha premido para mais opções',
|
||||
'Quick reaction emoji': 'Emoji de reação rápida',
|
||||
'Select emoji': 'Selecionar emoji'
|
||||
'Select emoji': 'Selecionar emoji',
|
||||
'NSFW content display': 'NSFW content display',
|
||||
'Hide completely': 'Hide completely',
|
||||
'Show but hide content': 'Show but hide content',
|
||||
'Show directly': 'Show directly',
|
||||
'Click to view': 'Click to view'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -583,6 +583,11 @@ export default {
|
||||
'If enabled, you can react with a single click. Click and hold for more options':
|
||||
'Если включено, вы можете реагировать одним щелчком. Нажмите и удерживайте для дополнительных параметров',
|
||||
'Quick reaction emoji': 'Эмодзи быстрой реакции',
|
||||
'Select emoji': 'Выбрать эмодзи'
|
||||
'Select emoji': 'Выбрать эмодзи',
|
||||
'NSFW content display': 'NSFW content display',
|
||||
'Hide completely': 'Hide completely',
|
||||
'Show but hide content': 'Show but hide content',
|
||||
'Show directly': 'Show directly',
|
||||
'Click to view': 'Click to view'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -570,6 +570,11 @@ export default {
|
||||
'If enabled, you can react with a single click. Click and hold for more options':
|
||||
'หากเปิดใช้งาน คุณสามารถรีแอคได้ด้วยคลิกเดียว คลิกค้างไว้สำหรับตัวเลือกเพิ่มเติม',
|
||||
'Quick reaction emoji': 'อีโมจิรีแอคชั่นด่วน',
|
||||
'Select emoji': 'เลือกอีโมจิ'
|
||||
'Select emoji': 'เลือกอีโมจิ',
|
||||
'NSFW content display': 'NSFW content display',
|
||||
'Hide completely': 'Hide completely',
|
||||
'Show but hide content': 'Show but hide content',
|
||||
'Show directly': 'Show directly',
|
||||
'Click to view': 'Click to view'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -563,6 +563,11 @@ export default {
|
||||
'If enabled, you can react with a single click. Click and hold for more options':
|
||||
'启用后,您可以通过单击进行点赞。长按以获取更多选项',
|
||||
'Quick reaction emoji': '快速点赞表情',
|
||||
'Select emoji': '选择表情'
|
||||
'Select emoji': '选择表情',
|
||||
'NSFW content display': 'NSFW 内容显示',
|
||||
'Hide completely': '完全隐藏',
|
||||
'Show but hide content': '显示但隐藏内容',
|
||||
'Show directly': '直接显示',
|
||||
'Click to view': '点击查看'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,14 @@ import { Button } from '@/components/ui/button'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger } from '@/components/ui/select'
|
||||
import { Switch } from '@/components/ui/switch'
|
||||
import { MEDIA_AUTO_LOAD_POLICY } from '@/constants'
|
||||
import { MEDIA_AUTO_LOAD_POLICY, NSFW_DISPLAY_POLICY } from '@/constants'
|
||||
import { LocalizedLanguageNames, TLanguage } from '@/i18n'
|
||||
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
|
||||
import { cn, isSupportCheckConnectionType } from '@/lib/utils'
|
||||
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
|
||||
import { useUserPreferences } from '@/providers/UserPreferencesProvider'
|
||||
import { useUserTrust } from '@/providers/UserTrustProvider'
|
||||
import { TMediaAutoLoadPolicy } from '@/types'
|
||||
import { TMediaAutoLoadPolicy, TNsfwDisplayPolicy } from '@/types'
|
||||
import { SelectValue } from '@radix-ui/react-select'
|
||||
import { RotateCcw } from 'lucide-react'
|
||||
import { forwardRef, HTMLProps, useState } from 'react'
|
||||
@@ -23,8 +23,8 @@ const GeneralSettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
|
||||
const {
|
||||
autoplay,
|
||||
setAutoplay,
|
||||
defaultShowNsfw,
|
||||
setDefaultShowNsfw,
|
||||
nsfwDisplayPolicy,
|
||||
setNsfwDisplayPolicy,
|
||||
hideContentMentioningMutedUsers,
|
||||
setHideContentMentioningMutedUsers,
|
||||
mediaAutoLoadPolicy,
|
||||
@@ -110,10 +110,24 @@ const GeneralSettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
|
||||
/>
|
||||
</SettingItem>
|
||||
<SettingItem>
|
||||
<Label htmlFor="show-nsfw" className="text-base font-normal">
|
||||
{t('Show NSFW content by default')}
|
||||
<Label htmlFor="nsfw-display-policy" className="text-base font-normal">
|
||||
{t('NSFW content display')}
|
||||
</Label>
|
||||
<Switch id="show-nsfw" checked={defaultShowNsfw} onCheckedChange={setDefaultShowNsfw} />
|
||||
<Select
|
||||
value={nsfwDisplayPolicy}
|
||||
onValueChange={(value: TNsfwDisplayPolicy) => setNsfwDisplayPolicy(value)}
|
||||
>
|
||||
<SelectTrigger id="nsfw-display-policy" className="w-48">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value={NSFW_DISPLAY_POLICY.HIDE}>{t('Hide completely')}</SelectItem>
|
||||
<SelectItem value={NSFW_DISPLAY_POLICY.HIDE_CONTENT}>
|
||||
{t('Show but hide content')}
|
||||
</SelectItem>
|
||||
<SelectItem value={NSFW_DISPLAY_POLICY.SHOW}>{t('Show directly')}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</SettingItem>
|
||||
<SettingItem>
|
||||
<Label htmlFor="quick-reaction" className="text-base font-normal">
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { MEDIA_AUTO_LOAD_POLICY } from '@/constants'
|
||||
import storage from '@/services/local-storage.service'
|
||||
import { TMediaAutoLoadPolicy } from '@/types'
|
||||
import { TMediaAutoLoadPolicy, TNsfwDisplayPolicy } from '@/types'
|
||||
import { createContext, useContext, useEffect, useMemo, useState } from 'react'
|
||||
|
||||
type TContentPolicyContext = {
|
||||
autoplay: boolean
|
||||
setAutoplay: (autoplay: boolean) => void
|
||||
|
||||
defaultShowNsfw: boolean
|
||||
setDefaultShowNsfw: (showNsfw: boolean) => void
|
||||
nsfwDisplayPolicy: TNsfwDisplayPolicy
|
||||
setNsfwDisplayPolicy: (policy: TNsfwDisplayPolicy) => void
|
||||
|
||||
hideContentMentioningMutedUsers?: boolean
|
||||
setHideContentMentioningMutedUsers?: (hide: boolean) => void
|
||||
@@ -33,7 +33,7 @@ export const useContentPolicy = () => {
|
||||
|
||||
export function ContentPolicyProvider({ children }: { children: React.ReactNode }) {
|
||||
const [autoplay, setAutoplay] = useState(storage.getAutoplay())
|
||||
const [defaultShowNsfw, setDefaultShowNsfw] = useState(storage.getDefaultShowNsfw())
|
||||
const [nsfwDisplayPolicy, setNsfwDisplayPolicy] = useState(storage.getNsfwDisplayPolicy())
|
||||
const [hideContentMentioningMutedUsers, setHideContentMentioningMutedUsers] = useState(
|
||||
storage.getHideContentMentioningMutedUsers()
|
||||
)
|
||||
@@ -72,9 +72,9 @@ export function ContentPolicyProvider({ children }: { children: React.ReactNode
|
||||
setAutoplay(autoplay)
|
||||
}
|
||||
|
||||
const updateDefaultShowNsfw = (defaultShowNsfw: boolean) => {
|
||||
storage.setDefaultShowNsfw(defaultShowNsfw)
|
||||
setDefaultShowNsfw(defaultShowNsfw)
|
||||
const updateNsfwDisplayPolicy = (policy: TNsfwDisplayPolicy) => {
|
||||
storage.setNsfwDisplayPolicy(policy)
|
||||
setNsfwDisplayPolicy(policy)
|
||||
}
|
||||
|
||||
const updateHideContentMentioningMutedUsers = (hide: boolean) => {
|
||||
@@ -97,8 +97,8 @@ export function ContentPolicyProvider({ children }: { children: React.ReactNode
|
||||
value={{
|
||||
autoplay,
|
||||
setAutoplay: updateAutoplay,
|
||||
defaultShowNsfw,
|
||||
setDefaultShowNsfw: updateDefaultShowNsfw,
|
||||
nsfwDisplayPolicy,
|
||||
setNsfwDisplayPolicy: updateNsfwDisplayPolicy,
|
||||
hideContentMentioningMutedUsers,
|
||||
setHideContentMentioningMutedUsers: updateHideContentMentioningMutedUsers,
|
||||
autoLoadMedia,
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
ExtendedKind,
|
||||
MEDIA_AUTO_LOAD_POLICY,
|
||||
NOTIFICATION_LIST_STYLE,
|
||||
NSFW_DISPLAY_POLICY,
|
||||
StorageKey,
|
||||
TPrimaryColor
|
||||
} from '@/constants'
|
||||
@@ -19,6 +20,7 @@ import {
|
||||
TMediaAutoLoadPolicy,
|
||||
TMediaUploadServiceConfig,
|
||||
TNoteListMode,
|
||||
TNsfwDisplayPolicy,
|
||||
TNotificationStyle,
|
||||
TRelaySet,
|
||||
TThemeSetting,
|
||||
@@ -46,7 +48,6 @@ class LocalStorageService {
|
||||
private hideUntrustedNotes: boolean = false
|
||||
private translationServiceConfigMap: Record<string, TTranslationServiceConfig> = {}
|
||||
private mediaUploadServiceConfigMap: Record<string, TMediaUploadServiceConfig> = {}
|
||||
private defaultShowNsfw: boolean = false
|
||||
private dismissedTooManyRelaysAlert: boolean = false
|
||||
private showKinds: number[] = []
|
||||
private hideContentMentioningMutedUsers: boolean = false
|
||||
@@ -60,6 +61,7 @@ class LocalStorageService {
|
||||
private filterOutOnionRelays: boolean = !isTorBrowser()
|
||||
private quickReaction: boolean = false
|
||||
private quickReactionEmoji: string | TEmoji = '+'
|
||||
private nsfwDisplayPolicy: TNsfwDisplayPolicy = NSFW_DISPLAY_POLICY.HIDE_CONTENT
|
||||
|
||||
constructor() {
|
||||
if (!LocalStorageService.instance) {
|
||||
@@ -161,7 +163,20 @@ class LocalStorageService {
|
||||
this.mediaUploadServiceConfigMap = JSON.parse(mediaUploadServiceConfigMapStr)
|
||||
}
|
||||
|
||||
this.defaultShowNsfw = window.localStorage.getItem(StorageKey.DEFAULT_SHOW_NSFW) === 'true'
|
||||
// Migrate old boolean setting to new policy
|
||||
const nsfwDisplayPolicyStr = window.localStorage.getItem(StorageKey.NSFW_DISPLAY_POLICY)
|
||||
if (
|
||||
nsfwDisplayPolicyStr &&
|
||||
Object.values(NSFW_DISPLAY_POLICY).includes(nsfwDisplayPolicyStr as TNsfwDisplayPolicy)
|
||||
) {
|
||||
this.nsfwDisplayPolicy = nsfwDisplayPolicyStr as TNsfwDisplayPolicy
|
||||
} else {
|
||||
// Migration: convert old boolean to new policy
|
||||
const defaultShowNsfwStr = window.localStorage.getItem(StorageKey.DEFAULT_SHOW_NSFW)
|
||||
this.nsfwDisplayPolicy =
|
||||
defaultShowNsfwStr === 'true' ? NSFW_DISPLAY_POLICY.SHOW : NSFW_DISPLAY_POLICY.HIDE_CONTENT
|
||||
window.localStorage.setItem(StorageKey.NSFW_DISPLAY_POLICY, this.nsfwDisplayPolicy)
|
||||
}
|
||||
|
||||
this.dismissedTooManyRelaysAlert =
|
||||
window.localStorage.getItem(StorageKey.DISMISSED_TOO_MANY_RELAYS_ALERT) === 'true'
|
||||
@@ -458,15 +473,6 @@ class LocalStorageService {
|
||||
return config
|
||||
}
|
||||
|
||||
getDefaultShowNsfw() {
|
||||
return this.defaultShowNsfw
|
||||
}
|
||||
|
||||
setDefaultShowNsfw(defaultShowNsfw: boolean) {
|
||||
this.defaultShowNsfw = defaultShowNsfw
|
||||
window.localStorage.setItem(StorageKey.DEFAULT_SHOW_NSFW, defaultShowNsfw.toString())
|
||||
}
|
||||
|
||||
getDismissedTooManyRelaysAlert() {
|
||||
return this.dismissedTooManyRelaysAlert
|
||||
}
|
||||
@@ -592,6 +598,15 @@ class LocalStorageService {
|
||||
typeof emoji === 'string' ? emoji : JSON.stringify(emoji)
|
||||
)
|
||||
}
|
||||
|
||||
getNsfwDisplayPolicy() {
|
||||
return this.nsfwDisplayPolicy
|
||||
}
|
||||
|
||||
setNsfwDisplayPolicy(policy: TNsfwDisplayPolicy) {
|
||||
this.nsfwDisplayPolicy = policy
|
||||
window.localStorage.setItem(StorageKey.NSFW_DISPLAY_POLICY, policy)
|
||||
}
|
||||
}
|
||||
|
||||
const instance = new LocalStorageService()
|
||||
|
||||
5
src/types/index.d.ts
vendored
5
src/types/index.d.ts
vendored
@@ -1,5 +1,5 @@
|
||||
import { Event, Filter, VerifiedEvent } from 'nostr-tools'
|
||||
import { MEDIA_AUTO_LOAD_POLICY, NOTIFICATION_LIST_STYLE, POLL_TYPE } from '../constants'
|
||||
import { MEDIA_AUTO_LOAD_POLICY, NOTIFICATION_LIST_STYLE, NSFW_DISPLAY_POLICY, POLL_TYPE } from '../constants'
|
||||
|
||||
export type TSubRequestFilter = Omit<Filter, 'since' | 'until'> & { limit: number }
|
||||
|
||||
@@ -205,3 +205,6 @@ export type TAwesomeRelayCollection = {
|
||||
|
||||
export type TMediaAutoLoadPolicy =
|
||||
(typeof MEDIA_AUTO_LOAD_POLICY)[keyof typeof MEDIA_AUTO_LOAD_POLICY]
|
||||
|
||||
export type TNsfwDisplayPolicy =
|
||||
(typeof NSFW_DISPLAY_POLICY)[keyof typeof NSFW_DISPLAY_POLICY]
|
||||
|
||||
Reference in New Issue
Block a user