diff --git a/src/components/UserAvatar/index.tsx b/src/components/UserAvatar/index.tsx index 3034068..3978aad 100644 --- a/src/components/UserAvatar/index.tsx +++ b/src/components/UserAvatar/index.tsx @@ -1,5 +1,6 @@ import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card' import { Skeleton } from '@/components/ui/skeleton' +import { useContentPolicy } from '@/providers/ContentPolicyProvider' import { useFetchProfile } from '@/hooks' import { toProfile } from '@/lib/link' import { generateImageByPubkey } from '@/lib/pubkey' @@ -63,6 +64,7 @@ export function SimpleUserAvatar({ onClick?: (e: React.MouseEvent) => void }) { const { profile } = useFetchProfile(userId) + const { autoLoadProfilePicture } = useContentPolicy() const defaultAvatar = useMemo( () => (profile?.pubkey ? generateImageByPubkey(profile.pubkey) : ''), [profile] @@ -75,9 +77,11 @@ export function SimpleUserAvatar({ } const { avatar, pubkey } = profile || {} + const imageUrl = autoLoadProfilePicture ? (avatar ?? defaultAvatar) : defaultAvatar + return ( (
) diff --git a/src/constants.ts b/src/constants.ts index 4b3f267..6902dda 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -34,6 +34,7 @@ export const StorageKey = { HIDE_CONTENT_MENTIONING_MUTED_USERS: 'hideContentMentioningMutedUsers', NOTIFICATION_LIST_STYLE: 'notificationListStyle', MEDIA_AUTO_LOAD_POLICY: 'mediaAutoLoadPolicy', + PROFILE_PICTURE_AUTO_LOAD_POLICY: 'profilePictureAutoLoadPolicy', SHOWN_CREATE_WALLET_GUIDE_TOAST_PUBKEYS: 'shownCreateWalletGuideToastPubkeys', SIDEBAR_COLLAPSE: 'sidebarCollapse', PRIMARY_COLOR: 'primaryColor', @@ -176,6 +177,12 @@ export const MEDIA_AUTO_LOAD_POLICY = { NEVER: 'never' } as const +export const PROFILE_PICTURE_AUTO_LOAD_POLICY = { + ALWAYS: 'always', + WIFI_ONLY: 'wifi-only', + NEVER: 'never' +} as const + export const NSFW_DISPLAY_POLICY = { HIDE: 'hide', HIDE_CONTENT: 'hide_content', diff --git a/src/i18n/locales/ar.ts b/src/i18n/locales/ar.ts index 42a86df..6486ac3 100644 --- a/src/i18n/locales/ar.ts +++ b/src/i18n/locales/ar.ts @@ -637,6 +637,7 @@ export default { Recommended: 'موصى به', 'Enter Password': 'أدخل كلمة المرور', Password: 'كلمة المرور', - Confirm: 'تأكيد' + Confirm: 'تأكيد', + 'Auto-load profile pictures': 'تحميل صور الملف الشخصي تلقائيًا' } } diff --git a/src/i18n/locales/de.ts b/src/i18n/locales/de.ts index 1eebbf9..05c118f 100644 --- a/src/i18n/locales/de.ts +++ b/src/i18n/locales/de.ts @@ -658,6 +658,7 @@ export default { Recommended: 'Empfohlen', 'Enter Password': 'Passwort eingeben', Password: 'Passwort', - Confirm: 'Bestätigen' + Confirm: 'Bestätigen', + 'Auto-load profile pictures': 'Profilbilder automatisch laden' } } diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts index 04f7159..c05add5 100644 --- a/src/i18n/locales/en.ts +++ b/src/i18n/locales/en.ts @@ -642,6 +642,7 @@ export default { Recommended: 'Recommended', 'Enter Password': 'Enter Password', Password: 'Password', - Confirm: 'Confirm' + Confirm: 'Confirm', + 'Auto-load profile pictures': 'Auto-load profile pictures' } } diff --git a/src/i18n/locales/es.ts b/src/i18n/locales/es.ts index 5404d26..f668d40 100644 --- a/src/i18n/locales/es.ts +++ b/src/i18n/locales/es.ts @@ -652,6 +652,7 @@ export default { Recommended: 'Recomendado', 'Enter Password': 'Ingresar contraseña', Password: 'Contraseña', - Confirm: 'Confirmar' + Confirm: 'Confirmar', + 'Auto-load profile pictures': 'Cargar imágenes de perfil automáticamente' } } diff --git a/src/i18n/locales/fa.ts b/src/i18n/locales/fa.ts index 1e13de5..fffd33c 100644 --- a/src/i18n/locales/fa.ts +++ b/src/i18n/locales/fa.ts @@ -647,6 +647,7 @@ export default { Recommended: 'توصیه شده', 'Enter Password': 'رمز عبور را وارد کنید', Password: 'رمز عبور', - Confirm: 'تأیید' + Confirm: 'تأیید', + 'Auto-load profile pictures': 'بارگذاری خودکار تصاویر پروفایل' } } diff --git a/src/i18n/locales/fr.ts b/src/i18n/locales/fr.ts index b3497f6..64d69df 100644 --- a/src/i18n/locales/fr.ts +++ b/src/i18n/locales/fr.ts @@ -655,6 +655,7 @@ export default { Recommended: 'Recommandé', 'Enter Password': 'Entrer le mot de passe', Password: 'Mot de passe', - Confirm: 'Confirmer' + Confirm: 'Confirmer', + 'Auto-load profile pictures': 'Charger les images de profil automatiquement' } } diff --git a/src/i18n/locales/hi.ts b/src/i18n/locales/hi.ts index 8f8af33..0a4db43 100644 --- a/src/i18n/locales/hi.ts +++ b/src/i18n/locales/hi.ts @@ -648,6 +648,7 @@ export default { Recommended: 'अनुशंसित', 'Enter Password': 'पासवर्ड दर्ज करें', Password: 'पासवर्ड', - Confirm: 'पुष्टि करें' + Confirm: 'पुष्टि करें', + 'Auto-load profile pictures': 'प्रोफ़ाइल चित्र स्वतः लोड करें' } } diff --git a/src/i18n/locales/hu.ts b/src/i18n/locales/hu.ts index b27e0c4..53f72b6 100644 --- a/src/i18n/locales/hu.ts +++ b/src/i18n/locales/hu.ts @@ -640,6 +640,7 @@ export default { Recommended: 'Ajánlott', 'Enter Password': 'Jelszó megadása', Password: 'Jelszó', - Confirm: 'Megerősítés' + Confirm: 'Megerősítés', + 'Auto-load profile pictures': 'Profilképek automatikus betöltése' } } diff --git a/src/i18n/locales/it.ts b/src/i18n/locales/it.ts index fe5e5c8..691122a 100644 --- a/src/i18n/locales/it.ts +++ b/src/i18n/locales/it.ts @@ -652,6 +652,7 @@ export default { Recommended: 'Consigliato', 'Enter Password': 'Inserisci password', Password: 'Password', - Confirm: 'Conferma' + Confirm: 'Conferma', + 'Auto-load profile pictures': 'Caricamento automatico immagini di profilo' } } diff --git a/src/i18n/locales/ja.ts b/src/i18n/locales/ja.ts index f722d74..95e810f 100644 --- a/src/i18n/locales/ja.ts +++ b/src/i18n/locales/ja.ts @@ -646,6 +646,7 @@ export default { Recommended: 'おすすめ', 'Enter Password': 'パスワードを入力', Password: 'パスワード', - Confirm: '確認' + Confirm: '確認', + 'Auto-load profile pictures': 'プロフィール画像を自動読み込み' } } diff --git a/src/i18n/locales/ko.ts b/src/i18n/locales/ko.ts index 03c3f9a..3adf98e 100644 --- a/src/i18n/locales/ko.ts +++ b/src/i18n/locales/ko.ts @@ -643,6 +643,7 @@ export default { Recommended: '추천', 'Enter Password': '비밀번호 입력', Password: '비밀번호', - Confirm: '확인' + Confirm: '확인', + 'Auto-load profile pictures': '프로필 사진 자동 로드' } } diff --git a/src/i18n/locales/pl.ts b/src/i18n/locales/pl.ts index bf0574d..d29282b 100644 --- a/src/i18n/locales/pl.ts +++ b/src/i18n/locales/pl.ts @@ -653,6 +653,7 @@ export default { Recommended: 'Polecane', 'Enter Password': 'Wprowadź hasło', Password: 'Hasło', - Confirm: 'Potwierdź' + Confirm: 'Potwierdź', + 'Auto-load profile pictures': 'Automatyczne ładowanie zdjęć profilowych' } } diff --git a/src/i18n/locales/pt-BR.ts b/src/i18n/locales/pt-BR.ts index 3426407..c4b4d73 100644 --- a/src/i18n/locales/pt-BR.ts +++ b/src/i18n/locales/pt-BR.ts @@ -648,6 +648,7 @@ export default { Recommended: 'Recomendado', 'Enter Password': 'Digite a senha', Password: 'Senha', - Confirm: 'Confirmar' + Confirm: 'Confirmar', + 'Auto-load profile pictures': 'Carregar fotos de perfil automaticamente' } } diff --git a/src/i18n/locales/pt-PT.ts b/src/i18n/locales/pt-PT.ts index d197ce7..6551793 100644 --- a/src/i18n/locales/pt-PT.ts +++ b/src/i18n/locales/pt-PT.ts @@ -651,6 +651,7 @@ export default { Recommended: 'Recomendado', 'Enter Password': 'Introduza a palavra-passe', Password: 'Palavra-passe', - Confirm: 'Confirmar' + Confirm: 'Confirmar', + 'Auto-load profile pictures': 'Carregar fotos de perfil automaticamente' } } diff --git a/src/i18n/locales/ru.ts b/src/i18n/locales/ru.ts index 385b980..5fcb2da 100644 --- a/src/i18n/locales/ru.ts +++ b/src/i18n/locales/ru.ts @@ -652,6 +652,7 @@ export default { Recommended: 'Рекомендуемые', 'Enter Password': 'Введите пароль', Password: 'Пароль', - Confirm: 'Подтвердить' + Confirm: 'Подтвердить', + 'Auto-load profile pictures': 'Автозагрузка аватаров' } } diff --git a/src/i18n/locales/th.ts b/src/i18n/locales/th.ts index 057815c..c67a2c2 100644 --- a/src/i18n/locales/th.ts +++ b/src/i18n/locales/th.ts @@ -637,6 +637,7 @@ export default { Recommended: 'แนะนำ', 'Enter Password': 'ป้อนรหัสผ่าน', Password: 'รหัสผ่าน', - Confirm: 'ยืนยัน' + Confirm: 'ยืนยัน', + 'Auto-load profile pictures': 'โหลดรูปโปรไฟล์อัตโนมัติ' } } diff --git a/src/i18n/locales/zh-TW.ts b/src/i18n/locales/zh-TW.ts index ba05eec..ae05086 100644 --- a/src/i18n/locales/zh-TW.ts +++ b/src/i18n/locales/zh-TW.ts @@ -623,6 +623,7 @@ export default { Recommended: '推薦', 'Enter Password': '輸入密碼', Password: '密碼', - Confirm: '確認' + Confirm: '確認', + 'Auto-load profile pictures': '自動載入大頭照' } } diff --git a/src/i18n/locales/zh.ts b/src/i18n/locales/zh.ts index f00c6c7..4db3eb8 100644 --- a/src/i18n/locales/zh.ts +++ b/src/i18n/locales/zh.ts @@ -628,6 +628,7 @@ export default { Recommended: '推荐', 'Enter Password': '输入密码', Password: '密码', - Confirm: '确认' + Confirm: '确认', + 'Auto-load profile pictures': '自动加载头像' } } diff --git a/src/lib/external-content.ts b/src/lib/external-content.ts index 7f5019a..aa9a5c9 100644 --- a/src/lib/external-content.ts +++ b/src/lib/external-content.ts @@ -23,7 +23,7 @@ export function determineExternalContentKind(externalContent: string): string | if (externalContent.startsWith('podcast:publisher:guid:')) { return 'podcast:publisher:guid' } - + // Handle blockchain transaction format: :[:]tx: // Match pattern: blockchain name, optional chain ID, "tx:", transaction ID const blockchainTxMatch = externalContent.match(/^([a-z]+):(?:[^:]+:)?tx:[a-f0-9]+$/i) @@ -31,10 +31,12 @@ export function determineExternalContentKind(externalContent: string): string | const blockchain = blockchainTxMatch[1].toLowerCase() return `${blockchain}:tx` } - + // Handle blockchain address format: :[:]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) { const blockchain = blockchainAddressMatch[1].toLowerCase() return `${blockchain}:address` diff --git a/src/lib/lightning.ts b/src/lib/lightning.ts index 76f967d..c703b3b 100644 --- a/src/lib/lightning.ts +++ b/src/lib/lightning.ts @@ -51,4 +51,4 @@ export function getLightningAddressFromProfile(profile: TProfile) { } return lud16 || lud06 || undefined -} \ No newline at end of file +} diff --git a/src/lib/tiptap.ts b/src/lib/tiptap.ts index eb7be0e..9339ede 100644 --- a/src/lib/tiptap.ts +++ b/src/lib/tiptap.ts @@ -7,25 +7,27 @@ export function parseEditorJsonToText(node?: JSONContent) { const text = _parseEditorJsonToText(node) const regex = /(^|\s+|@)(nostr:)?(nevent|naddr|nprofile|npub)1[a-zA-Z0-9]+/g - return text.replace(regex, (match, leadingWhitespace) => { - let bech32 = match.trim() - const whitespace = leadingWhitespace || '' + return text + .replace(regex, (match, leadingWhitespace) => { + let bech32 = match.trim() + const whitespace = leadingWhitespace || '' - if (bech32.startsWith('@nostr:')) { - bech32 = bech32.slice(7) - } else if (bech32.startsWith('@')) { - bech32 = bech32.slice(1) - } else if (bech32.startsWith('nostr:')) { - bech32 = bech32.slice(6) - } + if (bech32.startsWith('@nostr:')) { + bech32 = bech32.slice(7) + } else if (bech32.startsWith('@')) { + bech32 = bech32.slice(1) + } else if (bech32.startsWith('nostr:')) { + bech32 = bech32.slice(6) + } - try { - nip19.decode(bech32) - return `${whitespace}nostr:${bech32}` - } catch { - return match - } - }).trim() + try { + nip19.decode(bech32) + return `${whitespace}nostr:${bech32}` + } catch { + return match + } + }) + .trim() } function _parseEditorJsonToText(node?: JSONContent): string { diff --git a/src/pages/secondary/GeneralSettingsPage/index.tsx b/src/pages/secondary/GeneralSettingsPage/index.tsx index c5da59d..866e73d 100644 --- a/src/pages/secondary/GeneralSettingsPage/index.tsx +++ b/src/pages/secondary/GeneralSettingsPage/index.tsx @@ -4,14 +4,18 @@ 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, 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 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, TNsfwDisplayPolicy } from '@/types' +import { TMediaAutoLoadPolicy, TProfilePictureAutoLoadPolicy, TNsfwDisplayPolicy } from '@/types' import { SelectValue } from '@radix-ui/react-select' import { RotateCcw } from 'lucide-react' import { forwardRef, HTMLProps, useState } from 'react' @@ -28,7 +32,9 @@ const GeneralSettingsPage = forwardRef(({ index }: { index?: number }, ref) => { hideContentMentioningMutedUsers, setHideContentMentioningMutedUsers, mediaAutoLoadPolicy, - setMediaAutoLoadPolicy + setMediaAutoLoadPolicy, + profilePictureAutoLoadPolicy, + setProfilePictureAutoLoadPolicy } = useContentPolicy() const { hideUntrustedNotes, updateHideUntrustedNotes } = useUserTrust() const { quickReaction, updateQuickReaction, quickReactionEmoji, updateQuickReactionEmoji } = @@ -82,6 +88,31 @@ const GeneralSettingsPage = forwardRef(({ index }: { index?: number }, ref) => { + + + +