图片解密策略更加激进

This commit is contained in:
xuncha
2026-01-31 15:24:21 +08:00
parent b8dbc3caf1
commit 6e3bb9e361

View File

@@ -1501,6 +1501,10 @@ function MessageBubble({ message, session, showTime, myAvatarUrl, isGroupChat, o
const imageClickTimerRef = useRef<number | null>(null)
const imageContainerRef = useRef<HTMLDivElement>(null)
const imageAutoDecryptTriggered = useRef(false)
const imageAutoHdTriggered = useRef<string | null>(null)
const [imageInView, setImageInView] = useState(false)
const imageForceHdAttempted = useRef<string | null>(null)
const imageForceHdPending = useRef(false)
const [voiceError, setVoiceError] = useState(false)
const [voiceLoading, setVoiceLoading] = useState(false)
const [isVoicePlaying, setIsVoicePlaying] = useState(false)
@@ -1697,10 +1701,13 @@ function MessageBubble({ message, session, showTime, myAvatarUrl, isGroupChat, o
}
}, [isEmoji, message.emojiCdnUrl, emojiLocalPath, emojiLoading, emojiError])
const requestImageDecrypt = useCallback(async (forceUpdate = false) => {
if (!isImage || imageLoading) return
const requestImageDecrypt = useCallback(async (forceUpdate = false, silent = false) => {
if (!isImage) return
if (imageLoading) return
if (!silent) {
setImageLoading(true)
setImageError(false)
}
try {
if (message.imageMd5 || message.imageDatName) {
const result = await window.electronAPI.image.decrypt({
@@ -1726,14 +1733,25 @@ function MessageBubble({ message, session, showTime, myAvatarUrl, isGroupChat, o
setImageHasUpdate(false)
return
}
setImageError(true)
if (!silent) setImageError(true)
} catch {
setImageError(true)
if (!silent) setImageError(true)
} finally {
setImageLoading(false)
if (!silent) setImageLoading(false)
}
}, [isImage, imageLoading, message.imageMd5, message.imageDatName, message.localId, session.username, imageCacheKey, detectImageMimeFromBase64])
const triggerForceHd = useCallback(() => {
if (!message.imageMd5 && !message.imageDatName) return
if (imageForceHdAttempted.current === imageCacheKey) return
if (imageForceHdPending.current) return
imageForceHdAttempted.current = imageCacheKey
imageForceHdPending.current = true
requestImageDecrypt(true, true).finally(() => {
imageForceHdPending.current = false
})
}, [imageCacheKey, message.imageDatName, message.imageMd5, requestImageDecrypt])
const handleImageClick = useCallback(() => {
if (imageClickTimerRef.current) {
window.clearTimeout(imageClickTimerRef.current)
@@ -1846,6 +1864,47 @@ function MessageBubble({ message, session, showTime, myAvatarUrl, isGroupChat, o
return () => observer.disconnect()
}, [isImage, imageLocalPath, message.imageMd5, message.imageDatName, requestImageDecrypt])
// 进入视野时自动尝试切换高清图
useEffect(() => {
if (!isImage) return
const container = imageContainerRef.current
if (!container) return
const observer = new IntersectionObserver(
(entries) => {
const entry = entries[0]
setImageInView(entry.isIntersecting)
},
{ rootMargin: '120px', threshold: 0 }
)
observer.observe(container)
return () => observer.disconnect()
}, [isImage])
useEffect(() => {
if (!isImage || !imageHasUpdate || !imageInView) return
if (imageAutoHdTriggered.current === imageCacheKey) return
imageAutoHdTriggered.current = imageCacheKey
triggerForceHd()
}, [isImage, imageHasUpdate, imageInView, imageCacheKey, triggerForceHd])
useEffect(() => {
if (!isImage || !showImagePreview || !imageHasUpdate) return
if (imageAutoHdTriggered.current === imageCacheKey) return
imageAutoHdTriggered.current = imageCacheKey
triggerForceHd()
}, [isImage, showImagePreview, imageHasUpdate, imageCacheKey, triggerForceHd])
// 更激进:进入视野/打开预览时,无论 hasUpdate 与否都尝试强制高清
useEffect(() => {
if (!isImage || !imageInView) return
triggerForceHd()
}, [isImage, imageInView, triggerForceHd])
useEffect(() => {
if (!isImage || !showImagePreview) return
triggerForceHd()
}, [isImage, showImagePreview, triggerForceHd])
useEffect(() => {
if (!isVoice) return
@@ -2196,23 +2255,15 @@ function MessageBubble({ message, session, showTime, myAvatarUrl, isGroupChat, o
src={imageLocalPath}
alt="图片"
className="image-message"
onClick={() => setShowImagePreview(true)}
onClick={() => {
if (imageHasUpdate) {
void requestImageDecrypt(true, true)
}
setShowImagePreview(true)
}}
onLoad={() => setImageError(false)}
onError={() => setImageError(true)}
/>
{imageHasUpdate && (
<button
className="image-update-button"
type="button"
title="发现更高清图片,点击更新"
onClick={(event) => {
event.stopPropagation()
void requestImageDecrypt(true)
}}
>
<RefreshCw size={14} />
</button>
)}
</div>
{showImagePreview && (
<ImagePreview src={imageLocalPath} onClose={() => setShowImagePreview(false)} />