mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
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.
This commit is contained in:
@@ -3,7 +3,8 @@ import { FC, KeyboardEvent, useEffect, useRef, useState } from 'react';
|
|||||||
import { FaTimes } from 'react-icons/fa';
|
import { FaTimes } from 'react-icons/fa';
|
||||||
import { GetUserProfile, LocalizeText, ReportType, SendMessageComposer } from '../../../../api';
|
import { GetUserProfile, LocalizeText, ReportType, SendMessageComposer } from '../../../../api';
|
||||||
import { DraggableWindowPosition, LayoutAvatarImageView, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common';
|
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';
|
import { FriendsMessengerThreadView } from './messenger-thread/FriendsMessengerThreadView';
|
||||||
|
|
||||||
export const FriendsMessengerView: FC<{}> = props =>
|
export const FriendsMessengerView: FC<{}> = props =>
|
||||||
@@ -12,6 +13,7 @@ export const FriendsMessengerView: FC<{}> = props =>
|
|||||||
const [ lastThreadId, setLastThreadId ] = useState(-1);
|
const [ lastThreadId, setLastThreadId ] = useState(-1);
|
||||||
const [ messageText, setMessageText ] = useState('');
|
const [ messageText, setMessageText ] = useState('');
|
||||||
const { visibleThreads = [], activeThread = null, getMessageThread = null, sendMessage = null, setActiveThreadId = null, closeThread = null } = useMessenger();
|
const { visibleThreads = [], activeThread = null, getMessageThread = null, sendMessage = null, setActiveThreadId = null, closeThread = null } = useMessenger();
|
||||||
|
const { getFriend = null } = useFriends();
|
||||||
const { report = null } = useHelp();
|
const { report = null } = useHelp();
|
||||||
const { settings, translateOutgoing } = useTranslation();
|
const { settings, translateOutgoing } = useTranslation();
|
||||||
const messagesBox = useRef<HTMLDivElement>(null);
|
const messagesBox = useRef<HTMLDivElement>(null);
|
||||||
@@ -133,12 +135,22 @@ export const FriendsMessengerView: FC<{}> = props =>
|
|||||||
<div className="messenger-avatar-bar">
|
<div className="messenger-avatar-bar">
|
||||||
{ visibleThreads && (visibleThreads.length > 0) && visibleThreads.map(thread =>
|
{ 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 (
|
return (
|
||||||
<button key={ thread.threadId } className={ 'messenger-avatar-tab' + ((activeThread === thread) ? ' active' : '') + (thread.unread ? ' unread' : '') } onClick={ event => setActiveThreadId(thread.threadId) }>
|
<button key={ thread.threadId } className={ 'messenger-avatar-tab' + ((activeThread === thread) ? ' active' : '') + (thread.unread ? ' unread' : '') } onClick={ event => setActiveThreadId(thread.threadId) }>
|
||||||
<LayoutAvatarImageView
|
<LayoutAvatarImageView
|
||||||
figure={ thread.participant.id > 0 ? thread.participant.figure : 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 }
|
figure={ figure }
|
||||||
headOnly={ true }
|
headOnly={ true }
|
||||||
direction={ thread.participant.id > 0 ? 2 : 3 }
|
direction={ isStaff ? 3 : 2 }
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
|||||||
+4
-1
@@ -2,10 +2,13 @@ import { GetSessionDataManager } from '@nitrots/nitro-renderer';
|
|||||||
import { FC, useMemo } from 'react';
|
import { FC, useMemo } from 'react';
|
||||||
import { GetGroupChatData, LocalizeText, MessengerGroupType, MessengerThread, MessengerThreadChat, MessengerThreadChatGroup } from '../../../../../api';
|
import { GetGroupChatData, LocalizeText, MessengerGroupType, MessengerThread, MessengerThreadChat, MessengerThreadChatGroup } from '../../../../../api';
|
||||||
import { Base, Flex, LayoutAvatarImageView } from '../../../../../common';
|
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 =>
|
export const FriendsMessengerThreadGroup: FC<{ thread: MessengerThread, group: MessengerThreadChatGroup }> = props =>
|
||||||
{
|
{
|
||||||
const { thread = null, group = null } = 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 ]);
|
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
|
|||||||
<Flex fullWidth gap={ 2 } justifyContent={ isOwnChat ? 'end' : 'start' } className={ 'messenger-message-row ' + (isOwnChat ? 'own' : '') }>
|
<Flex fullWidth gap={ 2 } justifyContent={ isOwnChat ? 'end' : 'start' } className={ 'messenger-message-row ' + (isOwnChat ? 'own' : '') }>
|
||||||
<Base shrink className="message-avatar">
|
<Base shrink className="message-avatar">
|
||||||
{ ((group.type === MessengerGroupType.PRIVATE_CHAT) && !isOwnChat) &&
|
{ ((group.type === MessengerGroupType.PRIVATE_CHAT) && !isOwnChat) &&
|
||||||
<LayoutAvatarImageView direction={ 2 } figure={ thread.participant.figure } headOnly={ true } /> }
|
<LayoutAvatarImageView direction={ 2 } figure={ resolveAvatarFigure(getFriend?.(thread.participant.id)?.figure || thread.participant.figure, getFriend?.(thread.participant.id)?.gender ?? thread.participant.gender) } headOnly={ true } /> }
|
||||||
{ (groupChatData && !isOwnChat) &&
|
{ (groupChatData && !isOwnChat) &&
|
||||||
<LayoutAvatarImageView direction={ 2 } figure={ groupChatData.figure } headOnly={ true } /> }
|
<LayoutAvatarImageView direction={ 2 } figure={ groupChatData.figure } headOnly={ true } /> }
|
||||||
</Base>
|
</Base>
|
||||||
|
|||||||
@@ -537,14 +537,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
& .avatar-image {
|
& .avatar-image {
|
||||||
position: absolute;
|
position: absolute !important;
|
||||||
left: 50% !important;
|
inset: 0 !important;
|
||||||
top: -31px !important;
|
width: 100% !important;
|
||||||
width: 90px !important;
|
height: 100% !important;
|
||||||
height: 130px !important;
|
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
background-position: center -8px !important;
|
/* head-only image at native size (no scaling -> never grainy),
|
||||||
transform: translateX(-50%) !important;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user