fix: HTTP avatar image rendering issue
This commit is contained in:
parent
e4a61740c5
commit
5596e5eb7b
9 changed files with 40 additions and 33 deletions
|
|
@ -2,7 +2,7 @@ import { Button } from '@/components/ui/button'
|
||||||
import { Slider } from '@/components/ui/slider'
|
import { Slider } from '@/components/ui/slider'
|
||||||
import { isInsecureUrl } from '@/lib/url'
|
import { isInsecureUrl } from '@/lib/url'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import storage from '@/services/local-storage.service'
|
import { useUserPreferences } from '@/providers/UserPreferencesProvider'
|
||||||
import mediaManager from '@/services/media-manager.service'
|
import mediaManager from '@/services/media-manager.service'
|
||||||
import { Minimize2, Pause, Play, X } from 'lucide-react'
|
import { Minimize2, Pause, Play, X } from 'lucide-react'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
|
|
@ -24,6 +24,7 @@ export default function AudioPlayer({
|
||||||
className
|
className
|
||||||
}: AudioPlayerProps) {
|
}: AudioPlayerProps) {
|
||||||
const audioRef = useRef<HTMLAudioElement>(null)
|
const audioRef = useRef<HTMLAudioElement>(null)
|
||||||
|
const { allowInsecureConnection } = useUserPreferences()
|
||||||
const [isPlaying, setIsPlaying] = useState(false)
|
const [isPlaying, setIsPlaying] = useState(false)
|
||||||
const [currentTime, setCurrentTime] = useState(0)
|
const [currentTime, setCurrentTime] = useState(0)
|
||||||
const [duration, setDuration] = useState(0)
|
const [duration, setDuration] = useState(0)
|
||||||
|
|
@ -123,7 +124,7 @@ export default function AudioPlayer({
|
||||||
}, 300)
|
}, 300)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error || (!storage.getAllowInsecureConnection() && isInsecureUrl(src))) {
|
if (error || (!allowInsecureConnection && isInsecureUrl(src))) {
|
||||||
return <ExternalLink url={src} />
|
return <ExternalLink url={src} />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { isInsecureUrl } from '@/lib/url'
|
import { isInsecureUrl } from '@/lib/url'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import storage from '@/services/local-storage.service'
|
import { useUserPreferences } from '@/providers/UserPreferencesProvider'
|
||||||
import { TEmoji } from '@/types'
|
import { TEmoji } from '@/types'
|
||||||
import { Heart } from 'lucide-react'
|
import { Heart } from 'lucide-react'
|
||||||
import { HTMLAttributes, useState } from 'react'
|
import { HTMLAttributes, useState } from 'react'
|
||||||
|
|
@ -15,6 +15,7 @@ export default function Emoji({
|
||||||
img?: string
|
img?: string
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
|
const { allowInsecureConnection } = useUserPreferences()
|
||||||
const [hasError, setHasError] = useState(false)
|
const [hasError, setHasError] = useState(false)
|
||||||
|
|
||||||
if (typeof emoji === 'string') {
|
if (typeof emoji === 'string') {
|
||||||
|
|
@ -25,7 +26,7 @@ export default function Emoji({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasError || (!storage.getAllowInsecureConnection() && isInsecureUrl(emoji.url))) {
|
if (hasError || (!allowInsecureConnection && isInsecureUrl(emoji.url))) {
|
||||||
return (
|
return (
|
||||||
<span className={cn('whitespace-nowrap', classNames?.text)}>{`:${emoji.shortcode}:`}</span>
|
<span className={cn('whitespace-nowrap', classNames?.text)}>{`:${emoji.shortcode}:`}</span>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
import { Skeleton } from '@/components/ui/skeleton'
|
import { Skeleton } from '@/components/ui/skeleton'
|
||||||
import { isInsecureUrl } from '@/lib/url'
|
import { isInsecureUrl } from '@/lib/url'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
import { useUserPreferences } from '@/providers/UserPreferencesProvider'
|
||||||
import blossomService from '@/services/blossom.service'
|
import blossomService from '@/services/blossom.service'
|
||||||
import storage from '@/services/local-storage.service'
|
|
||||||
import { TImetaInfo } from '@/types'
|
import { TImetaInfo } from '@/types'
|
||||||
import { decode } from 'blurhash'
|
import { decode } from 'blurhash'
|
||||||
import { ImageOff } from 'lucide-react'
|
import { ImageOff } from 'lucide-react'
|
||||||
import { HTMLAttributes, useEffect, useMemo, useRef, useState } from 'react'
|
import { HTMLAttributes, useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { thumbHashToDataURL } from 'thumbhash'
|
import { thumbHashToDataURL } from 'thumbhash'
|
||||||
import ExternalLink from '../ExternalLink'
|
|
||||||
|
|
||||||
export default function Image({
|
export default function Image({
|
||||||
image: { url, blurHash, thumbHash, pubkey, dim },
|
image: { url, blurHash, thumbHash, pubkey, dim },
|
||||||
|
|
@ -29,21 +28,20 @@ export default function Image({
|
||||||
hideIfError?: boolean
|
hideIfError?: boolean
|
||||||
errorPlaceholder?: React.ReactNode
|
errorPlaceholder?: React.ReactNode
|
||||||
}) {
|
}) {
|
||||||
|
const { allowInsecureConnection } = useUserPreferences()
|
||||||
const [isLoading, setIsLoading] = useState(true)
|
const [isLoading, setIsLoading] = useState(true)
|
||||||
const [displaySkeleton, setDisplaySkeleton] = useState(true)
|
const [displaySkeleton, setDisplaySkeleton] = useState(true)
|
||||||
const [hasError, setHasError] = useState(false)
|
const [hasError, setHasError] = useState(false)
|
||||||
const [isBlocked, setIsBlocked] = useState(false)
|
|
||||||
const [imageUrl, setImageUrl] = useState<string>()
|
const [imageUrl, setImageUrl] = useState<string>()
|
||||||
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
setHasError(false)
|
setHasError(false)
|
||||||
setIsBlocked(false)
|
|
||||||
setDisplaySkeleton(true)
|
setDisplaySkeleton(true)
|
||||||
|
|
||||||
if (!storage.getAllowInsecureConnection() && isInsecureUrl(url)) {
|
if (!allowInsecureConnection && isInsecureUrl(url)) {
|
||||||
setIsBlocked(true)
|
setHasError(true)
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -62,11 +60,7 @@ export default function Image({
|
||||||
} else {
|
} else {
|
||||||
setImageUrl(url)
|
setImageUrl(url)
|
||||||
}
|
}
|
||||||
}, [url])
|
}, [url, allowInsecureConnection])
|
||||||
|
|
||||||
if (isBlocked) {
|
|
||||||
return <ExternalLink url={url} />
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hideIfError && hasError) return null
|
if (hideIfError && hasError) return null
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
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'
|
||||||
import { cn, isTouchDevice } from '@/lib/utils'
|
import { cn, isTouchDevice } from '@/lib/utils'
|
||||||
import { SecondaryPageLink } from '@/PageManager'
|
import { SecondaryPageLink } from '@/PageManager'
|
||||||
|
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import Image from '../Image'
|
import Image from '../Image'
|
||||||
import ProfileCard from '../ProfileCard'
|
import ProfileCard from '../ProfileCard'
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,13 @@ import { isInsecureUrl } from '@/lib/url'
|
||||||
import { cn, isInViewport } from '@/lib/utils'
|
import { cn, isInViewport } from '@/lib/utils'
|
||||||
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
|
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
|
||||||
import { useUserPreferences } from '@/providers/UserPreferencesProvider'
|
import { useUserPreferences } from '@/providers/UserPreferencesProvider'
|
||||||
import storage from '@/services/local-storage.service'
|
|
||||||
import mediaManager from '@/services/media-manager.service'
|
import mediaManager from '@/services/media-manager.service'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import ExternalLink from '../ExternalLink'
|
import ExternalLink from '../ExternalLink'
|
||||||
|
|
||||||
export default function VideoPlayer({ src, className }: { src: string; className?: string }) {
|
export default function VideoPlayer({ src, className }: { src: string; className?: string }) {
|
||||||
const { autoplay, videoLoop } = useContentPolicy()
|
const { autoplay, videoLoop } = useContentPolicy()
|
||||||
const { muteMedia, updateMuteMedia } = useUserPreferences()
|
const { muteMedia, updateMuteMedia, allowInsecureConnection } = useUserPreferences()
|
||||||
const [error, setError] = useState(false)
|
const [error, setError] = useState(false)
|
||||||
const videoRef = useRef<HTMLVideoElement>(null)
|
const videoRef = useRef<HTMLVideoElement>(null)
|
||||||
const containerRef = useRef<HTMLDivElement>(null)
|
const containerRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
@ -71,7 +70,7 @@ export default function VideoPlayer({ src, className }: { src: string; className
|
||||||
}
|
}
|
||||||
}, [muteMedia])
|
}, [muteMedia])
|
||||||
|
|
||||||
if (error || (!storage.getAllowInsecureConnection() && isInsecureUrl(src))) {
|
if (error || (!allowInsecureConnection && isInsecureUrl(src))) {
|
||||||
return <ExternalLink url={src} />
|
return <ExternalLink url={src} />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@ import { isInsecureUrl } from '@/lib/url'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
|
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
|
||||||
import { useScreenSize } from '@/providers/ScreenSizeProvider'
|
import { useScreenSize } from '@/providers/ScreenSizeProvider'
|
||||||
import storage from '@/services/local-storage.service'
|
import { useUserPreferences } from '@/providers/UserPreferencesProvider'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import Image from '../Image'
|
|
||||||
import ExternalLink from '../ExternalLink'
|
import ExternalLink from '../ExternalLink'
|
||||||
|
import Image from '../Image'
|
||||||
|
|
||||||
export default function WebPreview({
|
export default function WebPreview({
|
||||||
url,
|
url,
|
||||||
|
|
@ -18,6 +18,7 @@ export default function WebPreview({
|
||||||
mustLoad?: boolean
|
mustLoad?: boolean
|
||||||
}) {
|
}) {
|
||||||
const { autoLoadMedia } = useContentPolicy()
|
const { autoLoadMedia } = useContentPolicy()
|
||||||
|
const { allowInsecureConnection } = useUserPreferences()
|
||||||
const { isSmallScreen } = useScreenSize()
|
const { isSmallScreen } = useScreenSize()
|
||||||
const { title, description, image } = useFetchWebMetadata(url)
|
const { title, description, image } = useFetchWebMetadata(url)
|
||||||
|
|
||||||
|
|
@ -29,7 +30,7 @@ export default function WebPreview({
|
||||||
}
|
}
|
||||||
}, [url])
|
}, [url])
|
||||||
|
|
||||||
if (!storage.getAllowInsecureConnection() && isInsecureUrl(url)) {
|
if (!allowInsecureConnection && isInsecureUrl(url)) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import { isInsecureUrl } from '@/lib/url'
|
import { isInsecureUrl } from '@/lib/url'
|
||||||
import storage from '@/services/local-storage.service'
|
import { useUserPreferences } from '@/providers/UserPreferencesProvider'
|
||||||
import webService from '@/services/web.service'
|
import webService from '@/services/web.service'
|
||||||
import { TWebMetadata } from '@/types'
|
import { TWebMetadata } from '@/types'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
export function useFetchWebMetadata(url: string) {
|
export function useFetchWebMetadata(url: string) {
|
||||||
|
const { allowInsecureConnection } = useUserPreferences()
|
||||||
const [metadata, setMetadata] = useState<TWebMetadata>({})
|
const [metadata, setMetadata] = useState<TWebMetadata>({})
|
||||||
const proxyServer = import.meta.env.VITE_PROXY_SERVER
|
const proxyServer = import.meta.env.VITE_PROXY_SERVER
|
||||||
if (proxyServer) {
|
if (proxyServer) {
|
||||||
|
|
@ -12,10 +13,10 @@ export function useFetchWebMetadata(url: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!storage.getAllowInsecureConnection() && isInsecureUrl(url)) return
|
if (!allowInsecureConnection && isInsecureUrl(url)) return
|
||||||
|
|
||||||
webService.fetchWebMetadata(url).then((metadata) => setMetadata(metadata))
|
webService.fetchWebMetadata(url).then((metadata) => setMetadata(metadata))
|
||||||
}, [url])
|
}, [url, allowInsecureConnection])
|
||||||
|
|
||||||
return metadata
|
return metadata
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { Switch } from '@/components/ui/switch'
|
||||||
import { DEFAULT_FAVICON_URL_TEMPLATE } from '@/constants'
|
import { DEFAULT_FAVICON_URL_TEMPLATE } from '@/constants'
|
||||||
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
|
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
|
||||||
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
|
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
|
||||||
|
import { useUserPreferences } from '@/providers/UserPreferencesProvider'
|
||||||
import storage from '@/services/local-storage.service'
|
import storage from '@/services/local-storage.service'
|
||||||
import { forwardRef, useState } from 'react'
|
import { forwardRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
@ -13,12 +14,10 @@ import { useTranslation } from 'react-i18next'
|
||||||
const SystemSettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
|
const SystemSettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { faviconUrlTemplate, setFaviconUrlTemplate } = useContentPolicy()
|
const { faviconUrlTemplate, setFaviconUrlTemplate } = useContentPolicy()
|
||||||
|
const { allowInsecureConnection, updateAllowInsecureConnection } = useUserPreferences()
|
||||||
const [filterOutOnionRelays, setFilterOutOnionRelays] = useState(
|
const [filterOutOnionRelays, setFilterOutOnionRelays] = useState(
|
||||||
storage.getFilterOutOnionRelays()
|
storage.getFilterOutOnionRelays()
|
||||||
)
|
)
|
||||||
const [allowInsecureConnection, setAllowInsecureConnection] = useState(
|
|
||||||
storage.getAllowInsecureConnection()
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SecondaryPageLayout ref={ref} index={index} title={t('System')}>
|
<SecondaryPageLayout ref={ref} index={index} title={t('System')}>
|
||||||
|
|
@ -58,10 +57,7 @@ const SystemSettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
|
||||||
<Switch
|
<Switch
|
||||||
id="allow-insecure-connection"
|
id="allow-insecure-connection"
|
||||||
checked={allowInsecureConnection}
|
checked={allowInsecureConnection}
|
||||||
onCheckedChange={(checked) => {
|
onCheckedChange={updateAllowInsecureConnection}
|
||||||
storage.setAllowInsecureConnection(checked)
|
|
||||||
setAllowInsecureConnection(checked)
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2 px-4">
|
<div className="space-y-2 px-4">
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,9 @@ type TUserPreferencesContext = {
|
||||||
|
|
||||||
quickReactionEmoji: string | TEmoji
|
quickReactionEmoji: string | TEmoji
|
||||||
updateQuickReactionEmoji: (emoji: string | TEmoji) => void
|
updateQuickReactionEmoji: (emoji: string | TEmoji) => void
|
||||||
|
|
||||||
|
allowInsecureConnection: boolean
|
||||||
|
updateAllowInsecureConnection: (allow: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const UserPreferencesContext = createContext<TUserPreferencesContext | undefined>(undefined)
|
const UserPreferencesContext = createContext<TUserPreferencesContext | undefined>(undefined)
|
||||||
|
|
@ -46,6 +49,10 @@ export function UserPreferencesProvider({ children }: { children: React.ReactNod
|
||||||
const [quickReaction, setQuickReaction] = useState(storage.getQuickReaction())
|
const [quickReaction, setQuickReaction] = useState(storage.getQuickReaction())
|
||||||
const [quickReactionEmoji, setQuickReactionEmoji] = useState(storage.getQuickReactionEmoji())
|
const [quickReactionEmoji, setQuickReactionEmoji] = useState(storage.getQuickReactionEmoji())
|
||||||
|
|
||||||
|
const [allowInsecureConnection, setAllowInsecureConnection] = useState(
|
||||||
|
storage.getAllowInsecureConnection()
|
||||||
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isSmallScreen && enableSingleColumnLayout) {
|
if (!isSmallScreen && enableSingleColumnLayout) {
|
||||||
document.documentElement.style.setProperty('overflow-y', 'scroll')
|
document.documentElement.style.setProperty('overflow-y', 'scroll')
|
||||||
|
|
@ -79,6 +86,11 @@ export function UserPreferencesProvider({ children }: { children: React.ReactNod
|
||||||
storage.setQuickReactionEmoji(emoji)
|
storage.setQuickReactionEmoji(emoji)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateAllowInsecureConnection = (allow: boolean) => {
|
||||||
|
setAllowInsecureConnection(allow)
|
||||||
|
storage.setAllowInsecureConnection(allow)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UserPreferencesContext.Provider
|
<UserPreferencesContext.Provider
|
||||||
value={{
|
value={{
|
||||||
|
|
@ -93,7 +105,9 @@ export function UserPreferencesProvider({ children }: { children: React.ReactNod
|
||||||
quickReaction,
|
quickReaction,
|
||||||
updateQuickReaction,
|
updateQuickReaction,
|
||||||
quickReactionEmoji,
|
quickReactionEmoji,
|
||||||
updateQuickReactionEmoji
|
updateQuickReactionEmoji,
|
||||||
|
allowInsecureConnection,
|
||||||
|
updateAllowInsecureConnection
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue