From 1eb4d5594ba42d58d13c44896c64d1478b48e3e3 Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Sun, 7 Jun 2026 00:37:20 +0200 Subject: [PATCH] fix(messenger): show real avatar for offline friends + fix head framing The messenger rendered the participant figure straight from the frozen thread participant, so offline friends (whose look used to be empty) showed the anonymous/standard avatar. Read the live look from the friend list via getFriend() - the same source the friends list renders - with resolveAvatarFigure() as the final fallback, so the real avatar shows even when offline (pairs with the server fix that now sends offline looks). Applied to both the avatar-bar tab and the in-thread avatars. Also fix the avatar-tab head framing: it positioned the head-only image with full-body geometry (90x130, top:-31px), clipping the head. Render the head at native size (background-size:auto, no scaling -> not grainy) and centre it in the 36x36 tab. --- .../views/messenger/FriendsMessengerView.tsx | 18 +++++++++++++++--- .../FriendsMessengerThreadGroup.tsx | 5 ++++- src/css/friends/FriendsView.css | 18 +++++++++++------- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/components/friends/views/messenger/FriendsMessengerView.tsx b/src/components/friends/views/messenger/FriendsMessengerView.tsx index 0eaf484..b456b8b 100644 --- a/src/components/friends/views/messenger/FriendsMessengerView.tsx +++ b/src/components/friends/views/messenger/FriendsMessengerView.tsx @@ -3,7 +3,8 @@ import { FC, KeyboardEvent, useEffect, useRef, useState } from 'react'; import { FaTimes } from 'react-icons/fa'; import { GetUserProfile, LocalizeText, ReportType, SendMessageComposer } from '../../../../api'; import { DraggableWindowPosition, LayoutAvatarImageView, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common'; -import { useHelp, useMessenger, useTranslation } from '../../../../hooks'; +import { useFriends, useHelp, useMessenger, useTranslation } from '../../../../hooks'; +import { resolveAvatarFigure } from '../friends-list/resolveAvatarFigure'; import { FriendsMessengerThreadView } from './messenger-thread/FriendsMessengerThreadView'; export const FriendsMessengerView: FC<{}> = props => @@ -12,6 +13,7 @@ export const FriendsMessengerView: FC<{}> = props => const [ lastThreadId, setLastThreadId ] = useState(-1); const [ messageText, setMessageText ] = useState(''); const { visibleThreads = [], activeThread = null, getMessageThread = null, sendMessage = null, setActiveThreadId = null, closeThread = null } = useMessenger(); + const { getFriend = null } = useFriends(); const { report = null } = useHelp(); const { settings, translateOutgoing } = useTranslation(); const messagesBox = useRef(null); @@ -133,12 +135,22 @@ export const FriendsMessengerView: FC<{}> = props =>
{ visibleThreads && (visibleThreads.length > 0) && visibleThreads.map(thread => { + const isStaff = (thread.participant.id <= 0); + // Read the live look from the friend list (same source the friends + // list renders) so offline friends show their real avatar instead + // of the standard/anonymous one; resolveAvatarFigure is the final + // fallback when the look is genuinely missing. + const liveFriend = isStaff ? null : getFriend(thread.participant.id); + const figure = isStaff + ? (thread.participant.figure === 'ADM' ? 'ha-3409-1413-70.lg-285-89.ch-3032-1334-109.sh-3016-110.hd-185-1359.ca-3225-110-62.wa-3264-62-62.fa-1206-90.hr-3322-1403' : thread.participant.figure) + : resolveAvatarFigure(liveFriend?.figure || thread.participant.figure, liveFriend?.gender ?? thread.participant.gender); + return ( ); diff --git a/src/components/friends/views/messenger/messenger-thread/FriendsMessengerThreadGroup.tsx b/src/components/friends/views/messenger/messenger-thread/FriendsMessengerThreadGroup.tsx index 97d74bf..aed920c 100644 --- a/src/components/friends/views/messenger/messenger-thread/FriendsMessengerThreadGroup.tsx +++ b/src/components/friends/views/messenger/messenger-thread/FriendsMessengerThreadGroup.tsx @@ -2,10 +2,13 @@ import { GetSessionDataManager } from '@nitrots/nitro-renderer'; import { FC, useMemo } from 'react'; import { GetGroupChatData, LocalizeText, MessengerGroupType, MessengerThread, MessengerThreadChat, MessengerThreadChatGroup } from '../../../../../api'; import { Base, Flex, LayoutAvatarImageView } from '../../../../../common'; +import { useFriends } from '../../../../../hooks'; +import { resolveAvatarFigure } from '../../friends-list/resolveAvatarFigure'; export const FriendsMessengerThreadGroup: FC<{ thread: MessengerThread, group: MessengerThreadChatGroup }> = props => { const { thread = null, group = null } = props; + const { getFriend = null } = useFriends(); const groupChatData = useMemo(() => ((group.type === MessengerGroupType.GROUP_CHAT) && GetGroupChatData(group.chats[0].extraData)), [ group ]); @@ -50,7 +53,7 @@ export const FriendsMessengerThreadGroup: FC<{ thread: MessengerThread, group: M { ((group.type === MessengerGroupType.PRIVATE_CHAT) && !isOwnChat) && - } + } { (groupChatData && !isOwnChat) && } diff --git a/src/css/friends/FriendsView.css b/src/css/friends/FriendsView.css index 43be89c..41660ed 100644 --- a/src/css/friends/FriendsView.css +++ b/src/css/friends/FriendsView.css @@ -537,14 +537,18 @@ } & .avatar-image { - position: absolute; - left: 50% !important; - top: -31px !important; - width: 90px !important; - height: 130px !important; + position: absolute !important; + inset: 0 !important; + width: 100% !important; + height: 100% !important; margin: 0 !important; - background-position: center -8px !important; - transform: translateX(-50%) !important; + /* head-only image at native size (no scaling -> never grainy), + centred in the tab. Tweak the 2nd value of background-position + to raise (smaller %) or lower (larger %) the face. */ + background-size: auto !important; + background-position: center 35% !important; + transform: none !important; + image-rendering: pixelated !important; } }