feat: add auto-load profile pictures setting (#712)
This commit is contained in:
parent
ec03a49e32
commit
6dc662bd2b
28 changed files with 170 additions and 47 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card'
|
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card'
|
||||||
import { Skeleton } from '@/components/ui/skeleton'
|
import { Skeleton } from '@/components/ui/skeleton'
|
||||||
|
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
|
||||||
import { useFetchProfile } from '@/hooks'
|
import { useFetchProfile } from '@/hooks'
|
||||||
import { toProfile } from '@/lib/link'
|
import { toProfile } from '@/lib/link'
|
||||||
import { generateImageByPubkey } from '@/lib/pubkey'
|
import { generateImageByPubkey } from '@/lib/pubkey'
|
||||||
|
|
@ -63,6 +64,7 @@ export function SimpleUserAvatar({
|
||||||
onClick?: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void
|
onClick?: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void
|
||||||
}) {
|
}) {
|
||||||
const { profile } = useFetchProfile(userId)
|
const { profile } = useFetchProfile(userId)
|
||||||
|
const { autoLoadProfilePicture } = useContentPolicy()
|
||||||
const defaultAvatar = useMemo(
|
const defaultAvatar = useMemo(
|
||||||
() => (profile?.pubkey ? generateImageByPubkey(profile.pubkey) : ''),
|
() => (profile?.pubkey ? generateImageByPubkey(profile.pubkey) : ''),
|
||||||
[profile]
|
[profile]
|
||||||
|
|
@ -75,9 +77,11 @@ export function SimpleUserAvatar({
|
||||||
}
|
}
|
||||||
const { avatar, pubkey } = profile || {}
|
const { avatar, pubkey } = profile || {}
|
||||||
|
|
||||||
|
const imageUrl = autoLoadProfilePicture ? (avatar ?? defaultAvatar) : defaultAvatar
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Image
|
<Image
|
||||||
image={{ url: avatar ?? defaultAvatar, pubkey }}
|
image={{ url: imageUrl, pubkey }}
|
||||||
errorPlaceholder={defaultAvatar}
|
errorPlaceholder={defaultAvatar}
|
||||||
className="object-cover object-center"
|
className="object-cover object-center"
|
||||||
classNames={{
|
classNames={{
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,10 @@ const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElemen
|
||||||
({ className, ...props }, ref) => (
|
({ className, ...props }, ref) => (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn('rounded-xl border bg-card text-card-foreground transition-all duration-200', className)}
|
className={cn(
|
||||||
|
'rounded-xl border bg-card text-card-foreground transition-all duration-200',
|
||||||
|
className
|
||||||
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ export const StorageKey = {
|
||||||
HIDE_CONTENT_MENTIONING_MUTED_USERS: 'hideContentMentioningMutedUsers',
|
HIDE_CONTENT_MENTIONING_MUTED_USERS: 'hideContentMentioningMutedUsers',
|
||||||
NOTIFICATION_LIST_STYLE: 'notificationListStyle',
|
NOTIFICATION_LIST_STYLE: 'notificationListStyle',
|
||||||
MEDIA_AUTO_LOAD_POLICY: 'mediaAutoLoadPolicy',
|
MEDIA_AUTO_LOAD_POLICY: 'mediaAutoLoadPolicy',
|
||||||
|
PROFILE_PICTURE_AUTO_LOAD_POLICY: 'profilePictureAutoLoadPolicy',
|
||||||
SHOWN_CREATE_WALLET_GUIDE_TOAST_PUBKEYS: 'shownCreateWalletGuideToastPubkeys',
|
SHOWN_CREATE_WALLET_GUIDE_TOAST_PUBKEYS: 'shownCreateWalletGuideToastPubkeys',
|
||||||
SIDEBAR_COLLAPSE: 'sidebarCollapse',
|
SIDEBAR_COLLAPSE: 'sidebarCollapse',
|
||||||
PRIMARY_COLOR: 'primaryColor',
|
PRIMARY_COLOR: 'primaryColor',
|
||||||
|
|
@ -176,6 +177,12 @@ export const MEDIA_AUTO_LOAD_POLICY = {
|
||||||
NEVER: 'never'
|
NEVER: 'never'
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
|
export const PROFILE_PICTURE_AUTO_LOAD_POLICY = {
|
||||||
|
ALWAYS: 'always',
|
||||||
|
WIFI_ONLY: 'wifi-only',
|
||||||
|
NEVER: 'never'
|
||||||
|
} as const
|
||||||
|
|
||||||
export const NSFW_DISPLAY_POLICY = {
|
export const NSFW_DISPLAY_POLICY = {
|
||||||
HIDE: 'hide',
|
HIDE: 'hide',
|
||||||
HIDE_CONTENT: 'hide_content',
|
HIDE_CONTENT: 'hide_content',
|
||||||
|
|
|
||||||
|
|
@ -637,6 +637,7 @@ export default {
|
||||||
Recommended: 'موصى به',
|
Recommended: 'موصى به',
|
||||||
'Enter Password': 'أدخل كلمة المرور',
|
'Enter Password': 'أدخل كلمة المرور',
|
||||||
Password: 'كلمة المرور',
|
Password: 'كلمة المرور',
|
||||||
Confirm: 'تأكيد'
|
Confirm: 'تأكيد',
|
||||||
|
'Auto-load profile pictures': 'تحميل صور الملف الشخصي تلقائيًا'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -658,6 +658,7 @@ export default {
|
||||||
Recommended: 'Empfohlen',
|
Recommended: 'Empfohlen',
|
||||||
'Enter Password': 'Passwort eingeben',
|
'Enter Password': 'Passwort eingeben',
|
||||||
Password: 'Passwort',
|
Password: 'Passwort',
|
||||||
Confirm: 'Bestätigen'
|
Confirm: 'Bestätigen',
|
||||||
|
'Auto-load profile pictures': 'Profilbilder automatisch laden'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -642,6 +642,7 @@ export default {
|
||||||
Recommended: 'Recommended',
|
Recommended: 'Recommended',
|
||||||
'Enter Password': 'Enter Password',
|
'Enter Password': 'Enter Password',
|
||||||
Password: 'Password',
|
Password: 'Password',
|
||||||
Confirm: 'Confirm'
|
Confirm: 'Confirm',
|
||||||
|
'Auto-load profile pictures': 'Auto-load profile pictures'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -652,6 +652,7 @@ export default {
|
||||||
Recommended: 'Recomendado',
|
Recommended: 'Recomendado',
|
||||||
'Enter Password': 'Ingresar contraseña',
|
'Enter Password': 'Ingresar contraseña',
|
||||||
Password: 'Contraseña',
|
Password: 'Contraseña',
|
||||||
Confirm: 'Confirmar'
|
Confirm: 'Confirmar',
|
||||||
|
'Auto-load profile pictures': 'Cargar imágenes de perfil automáticamente'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -647,6 +647,7 @@ export default {
|
||||||
Recommended: 'توصیه شده',
|
Recommended: 'توصیه شده',
|
||||||
'Enter Password': 'رمز عبور را وارد کنید',
|
'Enter Password': 'رمز عبور را وارد کنید',
|
||||||
Password: 'رمز عبور',
|
Password: 'رمز عبور',
|
||||||
Confirm: 'تأیید'
|
Confirm: 'تأیید',
|
||||||
|
'Auto-load profile pictures': 'بارگذاری خودکار تصاویر پروفایل'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -655,6 +655,7 @@ export default {
|
||||||
Recommended: 'Recommandé',
|
Recommended: 'Recommandé',
|
||||||
'Enter Password': 'Entrer le mot de passe',
|
'Enter Password': 'Entrer le mot de passe',
|
||||||
Password: 'Mot de passe',
|
Password: 'Mot de passe',
|
||||||
Confirm: 'Confirmer'
|
Confirm: 'Confirmer',
|
||||||
|
'Auto-load profile pictures': 'Charger les images de profil automatiquement'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -648,6 +648,7 @@ export default {
|
||||||
Recommended: 'अनुशंसित',
|
Recommended: 'अनुशंसित',
|
||||||
'Enter Password': 'पासवर्ड दर्ज करें',
|
'Enter Password': 'पासवर्ड दर्ज करें',
|
||||||
Password: 'पासवर्ड',
|
Password: 'पासवर्ड',
|
||||||
Confirm: 'पुष्टि करें'
|
Confirm: 'पुष्टि करें',
|
||||||
|
'Auto-load profile pictures': 'प्रोफ़ाइल चित्र स्वतः लोड करें'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -640,6 +640,7 @@ export default {
|
||||||
Recommended: 'Ajánlott',
|
Recommended: 'Ajánlott',
|
||||||
'Enter Password': 'Jelszó megadása',
|
'Enter Password': 'Jelszó megadása',
|
||||||
Password: 'Jelszó',
|
Password: 'Jelszó',
|
||||||
Confirm: 'Megerősítés'
|
Confirm: 'Megerősítés',
|
||||||
|
'Auto-load profile pictures': 'Profilképek automatikus betöltése'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -652,6 +652,7 @@ export default {
|
||||||
Recommended: 'Consigliato',
|
Recommended: 'Consigliato',
|
||||||
'Enter Password': 'Inserisci password',
|
'Enter Password': 'Inserisci password',
|
||||||
Password: 'Password',
|
Password: 'Password',
|
||||||
Confirm: 'Conferma'
|
Confirm: 'Conferma',
|
||||||
|
'Auto-load profile pictures': 'Caricamento automatico immagini di profilo'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -646,6 +646,7 @@ export default {
|
||||||
Recommended: 'おすすめ',
|
Recommended: 'おすすめ',
|
||||||
'Enter Password': 'パスワードを入力',
|
'Enter Password': 'パスワードを入力',
|
||||||
Password: 'パスワード',
|
Password: 'パスワード',
|
||||||
Confirm: '確認'
|
Confirm: '確認',
|
||||||
|
'Auto-load profile pictures': 'プロフィール画像を自動読み込み'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -643,6 +643,7 @@ export default {
|
||||||
Recommended: '추천',
|
Recommended: '추천',
|
||||||
'Enter Password': '비밀번호 입력',
|
'Enter Password': '비밀번호 입력',
|
||||||
Password: '비밀번호',
|
Password: '비밀번호',
|
||||||
Confirm: '확인'
|
Confirm: '확인',
|
||||||
|
'Auto-load profile pictures': '프로필 사진 자동 로드'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -653,6 +653,7 @@ export default {
|
||||||
Recommended: 'Polecane',
|
Recommended: 'Polecane',
|
||||||
'Enter Password': 'Wprowadź hasło',
|
'Enter Password': 'Wprowadź hasło',
|
||||||
Password: 'Hasło',
|
Password: 'Hasło',
|
||||||
Confirm: 'Potwierdź'
|
Confirm: 'Potwierdź',
|
||||||
|
'Auto-load profile pictures': 'Automatyczne ładowanie zdjęć profilowych'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -648,6 +648,7 @@ export default {
|
||||||
Recommended: 'Recomendado',
|
Recommended: 'Recomendado',
|
||||||
'Enter Password': 'Digite a senha',
|
'Enter Password': 'Digite a senha',
|
||||||
Password: 'Senha',
|
Password: 'Senha',
|
||||||
Confirm: 'Confirmar'
|
Confirm: 'Confirmar',
|
||||||
|
'Auto-load profile pictures': 'Carregar fotos de perfil automaticamente'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -651,6 +651,7 @@ export default {
|
||||||
Recommended: 'Recomendado',
|
Recommended: 'Recomendado',
|
||||||
'Enter Password': 'Introduza a palavra-passe',
|
'Enter Password': 'Introduza a palavra-passe',
|
||||||
Password: 'Palavra-passe',
|
Password: 'Palavra-passe',
|
||||||
Confirm: 'Confirmar'
|
Confirm: 'Confirmar',
|
||||||
|
'Auto-load profile pictures': 'Carregar fotos de perfil automaticamente'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -652,6 +652,7 @@ export default {
|
||||||
Recommended: 'Рекомендуемые',
|
Recommended: 'Рекомендуемые',
|
||||||
'Enter Password': 'Введите пароль',
|
'Enter Password': 'Введите пароль',
|
||||||
Password: 'Пароль',
|
Password: 'Пароль',
|
||||||
Confirm: 'Подтвердить'
|
Confirm: 'Подтвердить',
|
||||||
|
'Auto-load profile pictures': 'Автозагрузка аватаров'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -637,6 +637,7 @@ export default {
|
||||||
Recommended: 'แนะนำ',
|
Recommended: 'แนะนำ',
|
||||||
'Enter Password': 'ป้อนรหัสผ่าน',
|
'Enter Password': 'ป้อนรหัสผ่าน',
|
||||||
Password: 'รหัสผ่าน',
|
Password: 'รหัสผ่าน',
|
||||||
Confirm: 'ยืนยัน'
|
Confirm: 'ยืนยัน',
|
||||||
|
'Auto-load profile pictures': 'โหลดรูปโปรไฟล์อัตโนมัติ'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -623,6 +623,7 @@ export default {
|
||||||
Recommended: '推薦',
|
Recommended: '推薦',
|
||||||
'Enter Password': '輸入密碼',
|
'Enter Password': '輸入密碼',
|
||||||
Password: '密碼',
|
Password: '密碼',
|
||||||
Confirm: '確認'
|
Confirm: '確認',
|
||||||
|
'Auto-load profile pictures': '自動載入大頭照'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -628,6 +628,7 @@ export default {
|
||||||
Recommended: '推荐',
|
Recommended: '推荐',
|
||||||
'Enter Password': '输入密码',
|
'Enter Password': '输入密码',
|
||||||
Password: '密码',
|
Password: '密码',
|
||||||
Confirm: '确认'
|
Confirm: '确认',
|
||||||
|
'Auto-load profile pictures': '自动加载头像'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,9 @@ export function determineExternalContentKind(externalContent: string): string |
|
||||||
|
|
||||||
// Handle blockchain address format: <blockchain>:[<chainId>:]address:<address>
|
// Handle blockchain address format: <blockchain>:[<chainId>:]address:<address>
|
||||||
// Match pattern: blockchain name, optional chain ID, "address:", address
|
// Match pattern: blockchain name, optional chain ID, "address:", address
|
||||||
const blockchainAddressMatch = externalContent.match(/^([a-z]+):(?:[^:]+:)?address:[a-zA-Z0-9]+$/i)
|
const blockchainAddressMatch = externalContent.match(
|
||||||
|
/^([a-z]+):(?:[^:]+:)?address:[a-zA-Z0-9]+$/i
|
||||||
|
)
|
||||||
if (blockchainAddressMatch) {
|
if (blockchainAddressMatch) {
|
||||||
const blockchain = blockchainAddressMatch[1].toLowerCase()
|
const blockchain = blockchainAddressMatch[1].toLowerCase()
|
||||||
return `${blockchain}:address`
|
return `${blockchain}:address`
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ export function parseEditorJsonToText(node?: JSONContent) {
|
||||||
const text = _parseEditorJsonToText(node)
|
const text = _parseEditorJsonToText(node)
|
||||||
const regex = /(^|\s+|@)(nostr:)?(nevent|naddr|nprofile|npub)1[a-zA-Z0-9]+/g
|
const regex = /(^|\s+|@)(nostr:)?(nevent|naddr|nprofile|npub)1[a-zA-Z0-9]+/g
|
||||||
|
|
||||||
return text.replace(regex, (match, leadingWhitespace) => {
|
return text
|
||||||
|
.replace(regex, (match, leadingWhitespace) => {
|
||||||
let bech32 = match.trim()
|
let bech32 = match.trim()
|
||||||
const whitespace = leadingWhitespace || ''
|
const whitespace = leadingWhitespace || ''
|
||||||
|
|
||||||
|
|
@ -25,7 +26,8 @@ export function parseEditorJsonToText(node?: JSONContent) {
|
||||||
} catch {
|
} catch {
|
||||||
return match
|
return match
|
||||||
}
|
}
|
||||||
}).trim()
|
})
|
||||||
|
.trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function _parseEditorJsonToText(node?: JSONContent): string {
|
function _parseEditorJsonToText(node?: JSONContent): string {
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,18 @@ import { Button } from '@/components/ui/button'
|
||||||
import { Label } from '@/components/ui/label'
|
import { Label } from '@/components/ui/label'
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger } from '@/components/ui/select'
|
import { Select, SelectContent, SelectItem, SelectTrigger } from '@/components/ui/select'
|
||||||
import { Switch } from '@/components/ui/switch'
|
import { Switch } from '@/components/ui/switch'
|
||||||
import { MEDIA_AUTO_LOAD_POLICY, NSFW_DISPLAY_POLICY } from '@/constants'
|
import {
|
||||||
|
MEDIA_AUTO_LOAD_POLICY,
|
||||||
|
NSFW_DISPLAY_POLICY,
|
||||||
|
PROFILE_PICTURE_AUTO_LOAD_POLICY
|
||||||
|
} from '@/constants'
|
||||||
import { LocalizedLanguageNames, TLanguage } from '@/i18n'
|
import { LocalizedLanguageNames, TLanguage } from '@/i18n'
|
||||||
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
|
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
|
||||||
import { cn, isSupportCheckConnectionType } from '@/lib/utils'
|
import { cn, isSupportCheckConnectionType } from '@/lib/utils'
|
||||||
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
|
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
|
||||||
import { useUserPreferences } from '@/providers/UserPreferencesProvider'
|
import { useUserPreferences } from '@/providers/UserPreferencesProvider'
|
||||||
import { useUserTrust } from '@/providers/UserTrustProvider'
|
import { useUserTrust } from '@/providers/UserTrustProvider'
|
||||||
import { TMediaAutoLoadPolicy, TNsfwDisplayPolicy } from '@/types'
|
import { TMediaAutoLoadPolicy, TProfilePictureAutoLoadPolicy, TNsfwDisplayPolicy } from '@/types'
|
||||||
import { SelectValue } from '@radix-ui/react-select'
|
import { SelectValue } from '@radix-ui/react-select'
|
||||||
import { RotateCcw } from 'lucide-react'
|
import { RotateCcw } from 'lucide-react'
|
||||||
import { forwardRef, HTMLProps, useState } from 'react'
|
import { forwardRef, HTMLProps, useState } from 'react'
|
||||||
|
|
@ -28,7 +32,9 @@ const GeneralSettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
|
||||||
hideContentMentioningMutedUsers,
|
hideContentMentioningMutedUsers,
|
||||||
setHideContentMentioningMutedUsers,
|
setHideContentMentioningMutedUsers,
|
||||||
mediaAutoLoadPolicy,
|
mediaAutoLoadPolicy,
|
||||||
setMediaAutoLoadPolicy
|
setMediaAutoLoadPolicy,
|
||||||
|
profilePictureAutoLoadPolicy,
|
||||||
|
setProfilePictureAutoLoadPolicy
|
||||||
} = useContentPolicy()
|
} = useContentPolicy()
|
||||||
const { hideUntrustedNotes, updateHideUntrustedNotes } = useUserTrust()
|
const { hideUntrustedNotes, updateHideUntrustedNotes } = useUserTrust()
|
||||||
const { quickReaction, updateQuickReaction, quickReactionEmoji, updateQuickReactionEmoji } =
|
const { quickReaction, updateQuickReaction, quickReactionEmoji, updateQuickReactionEmoji } =
|
||||||
|
|
@ -82,6 +88,31 @@ const GeneralSettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</SettingItem>
|
</SettingItem>
|
||||||
|
<SettingItem>
|
||||||
|
<Label htmlFor="profile-picture-auto-load-policy" className="text-base font-normal">
|
||||||
|
{t('Auto-load profile pictures')}
|
||||||
|
</Label>
|
||||||
|
<Select
|
||||||
|
defaultValue="always"
|
||||||
|
value={profilePictureAutoLoadPolicy}
|
||||||
|
onValueChange={(value: TProfilePictureAutoLoadPolicy) =>
|
||||||
|
setProfilePictureAutoLoadPolicy(value as TProfilePictureAutoLoadPolicy)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<SelectTrigger id="profile-picture-auto-load-policy" className="w-48">
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value={PROFILE_PICTURE_AUTO_LOAD_POLICY.ALWAYS}>{t('Always')}</SelectItem>
|
||||||
|
{isSupportCheckConnectionType() && (
|
||||||
|
<SelectItem value={PROFILE_PICTURE_AUTO_LOAD_POLICY.WIFI_ONLY}>
|
||||||
|
{t('Wi-Fi only')}
|
||||||
|
</SelectItem>
|
||||||
|
)}
|
||||||
|
<SelectItem value={PROFILE_PICTURE_AUTO_LOAD_POLICY.NEVER}>{t('Never')}</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</SettingItem>
|
||||||
<SettingItem>
|
<SettingItem>
|
||||||
<Label htmlFor="autoplay" className="text-base font-normal">
|
<Label htmlFor="autoplay" className="text-base font-normal">
|
||||||
<div>{t('Autoplay')}</div>
|
<div>{t('Autoplay')}</div>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { MEDIA_AUTO_LOAD_POLICY } from '@/constants'
|
import { MEDIA_AUTO_LOAD_POLICY, PROFILE_PICTURE_AUTO_LOAD_POLICY } from '@/constants'
|
||||||
import storage from '@/services/local-storage.service'
|
import storage from '@/services/local-storage.service'
|
||||||
import { TMediaAutoLoadPolicy, TNsfwDisplayPolicy } from '@/types'
|
import { TMediaAutoLoadPolicy, TProfilePictureAutoLoadPolicy, TNsfwDisplayPolicy } from '@/types'
|
||||||
import { createContext, useContext, useEffect, useMemo, useState } from 'react'
|
import { createContext, useContext, useEffect, useMemo, useState } from 'react'
|
||||||
|
|
||||||
type TContentPolicyContext = {
|
type TContentPolicyContext = {
|
||||||
|
|
@ -17,6 +17,10 @@ type TContentPolicyContext = {
|
||||||
mediaAutoLoadPolicy: TMediaAutoLoadPolicy
|
mediaAutoLoadPolicy: TMediaAutoLoadPolicy
|
||||||
setMediaAutoLoadPolicy: (policy: TMediaAutoLoadPolicy) => void
|
setMediaAutoLoadPolicy: (policy: TMediaAutoLoadPolicy) => void
|
||||||
|
|
||||||
|
autoLoadProfilePicture: boolean
|
||||||
|
profilePictureAutoLoadPolicy: TProfilePictureAutoLoadPolicy
|
||||||
|
setProfilePictureAutoLoadPolicy: (policy: TProfilePictureAutoLoadPolicy) => void
|
||||||
|
|
||||||
faviconUrlTemplate: string
|
faviconUrlTemplate: string
|
||||||
setFaviconUrlTemplate: (template: string) => void
|
setFaviconUrlTemplate: (template: string) => void
|
||||||
}
|
}
|
||||||
|
|
@ -38,6 +42,9 @@ export function ContentPolicyProvider({ children }: { children: React.ReactNode
|
||||||
storage.getHideContentMentioningMutedUsers()
|
storage.getHideContentMentioningMutedUsers()
|
||||||
)
|
)
|
||||||
const [mediaAutoLoadPolicy, setMediaAutoLoadPolicy] = useState(storage.getMediaAutoLoadPolicy())
|
const [mediaAutoLoadPolicy, setMediaAutoLoadPolicy] = useState(storage.getMediaAutoLoadPolicy())
|
||||||
|
const [profilePictureAutoLoadPolicy, setProfilePictureAutoLoadPolicy] = useState(
|
||||||
|
storage.getProfilePictureAutoLoadPolicy()
|
||||||
|
)
|
||||||
const [faviconUrlTemplate, setFaviconUrlTemplate] = useState(storage.getFaviconUrlTemplate())
|
const [faviconUrlTemplate, setFaviconUrlTemplate] = useState(storage.getFaviconUrlTemplate())
|
||||||
const [connectionType, setConnectionType] = useState((navigator as any).connection?.type)
|
const [connectionType, setConnectionType] = useState((navigator as any).connection?.type)
|
||||||
|
|
||||||
|
|
@ -67,6 +74,17 @@ export function ContentPolicyProvider({ children }: { children: React.ReactNode
|
||||||
return connectionType === 'wifi' || connectionType === 'ethernet'
|
return connectionType === 'wifi' || connectionType === 'ethernet'
|
||||||
}, [mediaAutoLoadPolicy, connectionType])
|
}, [mediaAutoLoadPolicy, connectionType])
|
||||||
|
|
||||||
|
const autoLoadProfilePicture = useMemo(() => {
|
||||||
|
if (profilePictureAutoLoadPolicy === PROFILE_PICTURE_AUTO_LOAD_POLICY.ALWAYS) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (profilePictureAutoLoadPolicy === PROFILE_PICTURE_AUTO_LOAD_POLICY.NEVER) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// WIFI_ONLY
|
||||||
|
return connectionType === 'wifi' || connectionType === 'ethernet'
|
||||||
|
}, [profilePictureAutoLoadPolicy, connectionType])
|
||||||
|
|
||||||
const updateAutoplay = (autoplay: boolean) => {
|
const updateAutoplay = (autoplay: boolean) => {
|
||||||
storage.setAutoplay(autoplay)
|
storage.setAutoplay(autoplay)
|
||||||
setAutoplay(autoplay)
|
setAutoplay(autoplay)
|
||||||
|
|
@ -87,6 +105,11 @@ export function ContentPolicyProvider({ children }: { children: React.ReactNode
|
||||||
setMediaAutoLoadPolicy(policy)
|
setMediaAutoLoadPolicy(policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateProfilePictureAutoLoadPolicy = (policy: TProfilePictureAutoLoadPolicy) => {
|
||||||
|
storage.setProfilePictureAutoLoadPolicy(policy)
|
||||||
|
setProfilePictureAutoLoadPolicy(policy)
|
||||||
|
}
|
||||||
|
|
||||||
const updateFaviconUrlTemplate = (template: string) => {
|
const updateFaviconUrlTemplate = (template: string) => {
|
||||||
storage.setFaviconUrlTemplate(template)
|
storage.setFaviconUrlTemplate(template)
|
||||||
setFaviconUrlTemplate(template)
|
setFaviconUrlTemplate(template)
|
||||||
|
|
@ -104,6 +127,9 @@ export function ContentPolicyProvider({ children }: { children: React.ReactNode
|
||||||
autoLoadMedia,
|
autoLoadMedia,
|
||||||
mediaAutoLoadPolicy,
|
mediaAutoLoadPolicy,
|
||||||
setMediaAutoLoadPolicy: updateMediaAutoLoadPolicy,
|
setMediaAutoLoadPolicy: updateMediaAutoLoadPolicy,
|
||||||
|
autoLoadProfilePicture,
|
||||||
|
profilePictureAutoLoadPolicy,
|
||||||
|
setProfilePictureAutoLoadPolicy: updateProfilePictureAutoLoadPolicy,
|
||||||
faviconUrlTemplate,
|
faviconUrlTemplate,
|
||||||
setFaviconUrlTemplate: updateFaviconUrlTemplate
|
setFaviconUrlTemplate: updateFaviconUrlTemplate
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import {
|
||||||
MEDIA_AUTO_LOAD_POLICY,
|
MEDIA_AUTO_LOAD_POLICY,
|
||||||
NOTIFICATION_LIST_STYLE,
|
NOTIFICATION_LIST_STYLE,
|
||||||
NSFW_DISPLAY_POLICY,
|
NSFW_DISPLAY_POLICY,
|
||||||
|
PROFILE_PICTURE_AUTO_LOAD_POLICY,
|
||||||
StorageKey,
|
StorageKey,
|
||||||
TPrimaryColor
|
TPrimaryColor
|
||||||
} from '@/constants'
|
} from '@/constants'
|
||||||
|
|
@ -20,6 +21,7 @@ import {
|
||||||
TMediaAutoLoadPolicy,
|
TMediaAutoLoadPolicy,
|
||||||
TMediaUploadServiceConfig,
|
TMediaUploadServiceConfig,
|
||||||
TNoteListMode,
|
TNoteListMode,
|
||||||
|
TProfilePictureAutoLoadPolicy,
|
||||||
TNsfwDisplayPolicy,
|
TNsfwDisplayPolicy,
|
||||||
TNotificationStyle,
|
TNotificationStyle,
|
||||||
TRelaySet,
|
TRelaySet,
|
||||||
|
|
@ -53,6 +55,8 @@ class LocalStorageService {
|
||||||
private hideContentMentioningMutedUsers: boolean = false
|
private hideContentMentioningMutedUsers: boolean = false
|
||||||
private notificationListStyle: TNotificationStyle = NOTIFICATION_LIST_STYLE.DETAILED
|
private notificationListStyle: TNotificationStyle = NOTIFICATION_LIST_STYLE.DETAILED
|
||||||
private mediaAutoLoadPolicy: TMediaAutoLoadPolicy = MEDIA_AUTO_LOAD_POLICY.ALWAYS
|
private mediaAutoLoadPolicy: TMediaAutoLoadPolicy = MEDIA_AUTO_LOAD_POLICY.ALWAYS
|
||||||
|
private profilePictureAutoLoadPolicy: TProfilePictureAutoLoadPolicy =
|
||||||
|
PROFILE_PICTURE_AUTO_LOAD_POLICY.ALWAYS
|
||||||
private shownCreateWalletGuideToastPubkeys: Set<string> = new Set()
|
private shownCreateWalletGuideToastPubkeys: Set<string> = new Set()
|
||||||
private sidebarCollapse: boolean = false
|
private sidebarCollapse: boolean = false
|
||||||
private primaryColor: TPrimaryColor = 'DEFAULT'
|
private primaryColor: TPrimaryColor = 'DEFAULT'
|
||||||
|
|
@ -225,6 +229,19 @@ class LocalStorageService {
|
||||||
this.mediaAutoLoadPolicy = mediaAutoLoadPolicy as TMediaAutoLoadPolicy
|
this.mediaAutoLoadPolicy = mediaAutoLoadPolicy as TMediaAutoLoadPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const profilePictureAutoLoadPolicy = window.localStorage.getItem(
|
||||||
|
StorageKey.PROFILE_PICTURE_AUTO_LOAD_POLICY
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
profilePictureAutoLoadPolicy &&
|
||||||
|
Object.values(PROFILE_PICTURE_AUTO_LOAD_POLICY).includes(
|
||||||
|
profilePictureAutoLoadPolicy as TProfilePictureAutoLoadPolicy
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
this.profilePictureAutoLoadPolicy =
|
||||||
|
profilePictureAutoLoadPolicy as TProfilePictureAutoLoadPolicy
|
||||||
|
}
|
||||||
|
|
||||||
const shownCreateWalletGuideToastPubkeysStr = window.localStorage.getItem(
|
const shownCreateWalletGuideToastPubkeysStr = window.localStorage.getItem(
|
||||||
StorageKey.SHOWN_CREATE_WALLET_GUIDE_TOAST_PUBKEYS
|
StorageKey.SHOWN_CREATE_WALLET_GUIDE_TOAST_PUBKEYS
|
||||||
)
|
)
|
||||||
|
|
@ -518,6 +535,15 @@ class LocalStorageService {
|
||||||
window.localStorage.setItem(StorageKey.MEDIA_AUTO_LOAD_POLICY, policy)
|
window.localStorage.setItem(StorageKey.MEDIA_AUTO_LOAD_POLICY, policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getProfilePictureAutoLoadPolicy() {
|
||||||
|
return this.profilePictureAutoLoadPolicy
|
||||||
|
}
|
||||||
|
|
||||||
|
setProfilePictureAutoLoadPolicy(policy: TProfilePictureAutoLoadPolicy) {
|
||||||
|
this.profilePictureAutoLoadPolicy = policy
|
||||||
|
window.localStorage.setItem(StorageKey.PROFILE_PICTURE_AUTO_LOAD_POLICY, policy)
|
||||||
|
}
|
||||||
|
|
||||||
hasShownCreateWalletGuideToast(pubkey: string) {
|
hasShownCreateWalletGuideToast(pubkey: string) {
|
||||||
return this.shownCreateWalletGuideToastPubkeys.has(pubkey)
|
return this.shownCreateWalletGuideToastPubkeys.has(pubkey)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6
src/types/index.d.ts
vendored
6
src/types/index.d.ts
vendored
|
|
@ -3,7 +3,8 @@ import {
|
||||||
MEDIA_AUTO_LOAD_POLICY,
|
MEDIA_AUTO_LOAD_POLICY,
|
||||||
NOTIFICATION_LIST_STYLE,
|
NOTIFICATION_LIST_STYLE,
|
||||||
NSFW_DISPLAY_POLICY,
|
NSFW_DISPLAY_POLICY,
|
||||||
POLL_TYPE
|
POLL_TYPE,
|
||||||
|
PROFILE_PICTURE_AUTO_LOAD_POLICY
|
||||||
} from '../constants'
|
} from '../constants'
|
||||||
|
|
||||||
export type TSubRequestFilter = Omit<Filter, 'since' | 'until'> & { limit: number }
|
export type TSubRequestFilter = Omit<Filter, 'since' | 'until'> & { limit: number }
|
||||||
|
|
@ -211,4 +212,7 @@ export type TAwesomeRelayCollection = {
|
||||||
export type TMediaAutoLoadPolicy =
|
export type TMediaAutoLoadPolicy =
|
||||||
(typeof MEDIA_AUTO_LOAD_POLICY)[keyof typeof MEDIA_AUTO_LOAD_POLICY]
|
(typeof MEDIA_AUTO_LOAD_POLICY)[keyof typeof MEDIA_AUTO_LOAD_POLICY]
|
||||||
|
|
||||||
|
export type TProfilePictureAutoLoadPolicy =
|
||||||
|
(typeof PROFILE_PICTURE_AUTO_LOAD_POLICY)[keyof typeof PROFILE_PICTURE_AUTO_LOAD_POLICY]
|
||||||
|
|
||||||
export type TNsfwDisplayPolicy = (typeof NSFW_DISPLAY_POLICY)[keyof typeof NSFW_DISPLAY_POLICY]
|
export type TNsfwDisplayPolicy = (typeof NSFW_DISPLAY_POLICY)[keyof typeof NSFW_DISPLAY_POLICY]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue