Update chat

This commit is contained in:
Bill 2022-11-13 20:59:55 -05:00
parent 1d782ebbf5
commit 1a8bf75a0d
4 changed files with 90 additions and 29 deletions

View File

@ -8,7 +8,6 @@ export class ChatBubbleMessage
public width: number = 0; public width: number = 0;
public height: number = 0; public height: number = 0;
public elementRef: HTMLDivElement = null; public elementRef: HTMLDivElement = null;
public visible: boolean = false;
public skipMovement: boolean = false; public skipMovement: boolean = false;
private _top: number = 0; private _top: number = 0;

View File

@ -6,13 +6,15 @@ interface ChatWidgetMessageViewProps
{ {
chat: ChatBubbleMessage; chat: ChatBubbleMessage;
makeRoom: (chat: ChatBubbleMessage) => void; makeRoom: (chat: ChatBubbleMessage) => void;
onBubbleReady?: () => void;
bubbleWidth?: number; bubbleWidth?: number;
} }
export const ChatWidgetMessageView: FC<ChatWidgetMessageViewProps> = props => export const ChatWidgetMessageView: FC<ChatWidgetMessageViewProps> = props =>
{ {
const { chat = null, makeRoom = null, bubbleWidth = RoomChatSettings.CHAT_BUBBLE_WIDTH_NORMAL } = props; const { chat = null, makeRoom = null, onBubbleReady = null, bubbleWidth = RoomChatSettings.CHAT_BUBBLE_WIDTH_NORMAL } = props;
const [ isVisible, setIsVisible ] = useState(false); const [ isVisible, setIsVisible ] = useState(false);
const [ isReady, setIsReady ] = useState<boolean>(false);
const elementRef = useRef<HTMLDivElement>(); const elementRef = useRef<HTMLDivElement>();
const getBubbleWidth = useMemo(() => const getBubbleWidth = useMemo(() =>
@ -30,6 +32,8 @@ export const ChatWidgetMessageView: FC<ChatWidgetMessageViewProps> = props =>
useEffect(() => useEffect(() =>
{ {
setIsVisible(false);
const element = elementRef.current; const element = elementRef.current;
if(!element) return; if(!element) return;
@ -53,20 +57,26 @@ export const ChatWidgetMessageView: FC<ChatWidgetMessageViewProps> = props =>
chat.top = top; chat.top = top;
} }
if(!chat.visible) setIsReady(true);
{
makeRoom(chat);
chat.visible = true;
}
return () => return () =>
{ {
chat.elementRef = null; chat.elementRef = null;
}
}, [ elementRef, chat, makeRoom ]);
useEffect(() => setIsVisible(chat.visible), [ chat.visible ]); setIsReady(false);
}
}, [ chat ]);
useEffect(() =>
{
if(!isReady || !chat || isVisible) return;
if(makeRoom) makeRoom(chat);
if(onBubbleReady) onBubbleReady();
setIsVisible(true);
}, [ chat, isReady, isVisible, makeRoom, onBubbleReady ]);
return ( return (
<div ref={ elementRef } className={ `bubble-container ${ isVisible ? 'visible' : 'invisible' }` } onClick={ event => GetRoomEngine().selectRoomObject(chat.roomId, chat.senderId, RoomObjectCategory.UNIT) }> <div ref={ elementRef } className={ `bubble-container ${ isVisible ? 'visible' : 'invisible' }` } onClick={ event => GetRoomEngine().selectRoomObject(chat.roomId, chat.senderId, RoomObjectCategory.UNIT) }>

View File

@ -1,5 +1,5 @@
import { IWorkerEventTracker, RoomChatSettings } from '@nitrots/nitro-renderer'; import { IWorkerEventTracker, RoomChatSettings } from '@nitrots/nitro-renderer';
import { FC, useEffect, useRef, useState } from 'react'; import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { AddWorkerEventTracker, ChatBubbleMessage, DoChatsOverlap, GetConfiguration, RemoveWorkerEventTracker, SendWorkerEvent } from '../../../../api'; import { AddWorkerEventTracker, ChatBubbleMessage, DoChatsOverlap, GetConfiguration, RemoveWorkerEventTracker, SendWorkerEvent } from '../../../../api';
import { useChatWidget } from '../../../../hooks'; import { useChatWidget } from '../../../../hooks';
import { ChatWidgetMessageView } from './ChatWidgetMessageView'; import { ChatWidgetMessageView } from './ChatWidgetMessageView';
@ -9,18 +9,35 @@ let TIMER_TRACKER: number = 0;
export const ChatWidgetView: FC<{}> = props => export const ChatWidgetView: FC<{}> = props =>
{ {
const [ timerId, setTimerId ] = useState(TIMER_TRACKER++); const [ timerId, setTimerId ] = useState(TIMER_TRACKER++);
const { chatMessages = [], setChatMessages = null, chatSettings = null, getScrollSpeed = 6000, removeHiddenChats = null, moveAllChatsUp = null } = useChatWidget(); const { pendingChats = null, chatSettings = null, getScrollSpeed = 6000, moveAllChatsUp = null } = useChatWidget();
const [ renderedChats, setRenderedChats ] = useState<ChatBubbleMessage[]>([]);
const elementRef = useRef<HTMLDivElement>(); const elementRef = useRef<HTMLDivElement>();
const isProcessing = useRef<boolean>(false);
const checkOverlappingChats = (chat: ChatBubbleMessage, moved: number, tempChats: ChatBubbleMessage[]) => const removeHiddenChats = useCallback(() =>
{ {
const totalChats = chatMessages.length; setRenderedChats(prevValue =>
{
if(prevValue)
{
const newMessages = prevValue.filter(chat => ((chat.top > (-(chat.height) * 2))));
if(newMessages.length !== prevValue.length) return newMessages;
}
return prevValue;
})
}, []);
const checkOverlappingChats = useCallback((chat: ChatBubbleMessage, moved: number, tempChats: ChatBubbleMessage[]) =>
{
const totalChats = renderedChats.length;
if(!totalChats) return; if(!totalChats) return;
for(let i = (totalChats - 1); i >= 0; i--) for(let i = (totalChats - 1); i >= 0; i--)
{ {
const collides = chatMessages[i]; const collides = renderedChats[i];
if(!collides || (chat === collides) || (tempChats.indexOf(collides) >= 0) || (((collides.top + collides.height) - moved) > (chat.top + chat.height))) continue; if(!collides || (chat === collides) || (tempChats.indexOf(collides) >= 0) || (((collides.top + collides.height) - moved) > (chat.top + chat.height))) continue;
@ -38,9 +55,9 @@ export const ChatWidgetView: FC<{}> = props =>
checkOverlappingChats(collides, amount, tempChats); checkOverlappingChats(collides, amount, tempChats);
} }
} }
} }, [ renderedChats ]);
const makeRoom = (chat: ChatBubbleMessage) => const makeRoom = useCallback((chat: ChatBubbleMessage) =>
{ {
if(chatSettings.mode === RoomChatSettings.CHAT_MODE_FREE_FLOW) if(chatSettings.mode === RoomChatSettings.CHAT_MODE_FREE_FLOW)
{ {
@ -59,17 +76,50 @@ export const ChatWidgetView: FC<{}> = props =>
if(spaceAvailable < requiredSpace) if(spaceAvailable < requiredSpace)
{ {
chatMessages.forEach(existingChat => setRenderedChats(prevValue =>
{ {
if(existingChat === chat) return; prevValue.forEach(prevChat =>
{
if(prevChat === chat) return;
existingChat.top -= amount; prevChat.top -= amount;
});
return prevValue;
}); });
removeHiddenChats(); removeHiddenChats();
} }
} }
} }, [ chatSettings, checkOverlappingChats, removeHiddenChats ]);
const onBubbleReady = useCallback(() =>
{
isProcessing.current = false;
}, []);
useEffect(() =>
{
const processNextChat = () =>
{
if(isProcessing.current) return;
const chat = pendingChats?.current?.shift();
if(!chat) return;
isProcessing.current = true;
setRenderedChats(prevValue => [ ...prevValue, chat ]);
}
const interval = setInterval(() => processNextChat(), 50);
return () =>
{
clearInterval(interval);
}
}, [ pendingChats ]);
useEffect(() => useEffect(() =>
{ {
@ -82,7 +132,7 @@ export const ChatWidgetView: FC<{}> = props =>
elementRef.current.style.height = `${ newHeight }px`; elementRef.current.style.height = `${ newHeight }px`;
setChatMessages(prevValue => setRenderedChats(prevValue =>
{ {
if(prevValue) if(prevValue)
{ {
@ -101,7 +151,7 @@ export const ChatWidgetView: FC<{}> = props =>
{ {
window.removeEventListener('resize', resize); window.removeEventListener('resize', resize);
} }
}, [ setChatMessages ]); }, []);
useEffect(() => useEffect(() =>
{ {
@ -139,7 +189,7 @@ export const ChatWidgetView: FC<{}> = props =>
return ( return (
<div ref={ elementRef } className="nitro-chat-widget"> <div ref={ elementRef } className="nitro-chat-widget">
{ chatMessages.map(chat => <ChatWidgetMessageView key={ chat.id } chat={ chat } makeRoom={ makeRoom } bubbleWidth={ chatSettings.weight } />) } { renderedChats.map(chat => <ChatWidgetMessageView key={ chat.id } chat={ chat } makeRoom={ makeRoom } onBubbleReady={ onBubbleReady } bubbleWidth={ chatSettings.weight } />) }
</div> </div>
); );
} }

View File

@ -1,5 +1,5 @@
import { AvatarFigurePartType, AvatarScaleType, AvatarSetType, GetGuestRoomResultEvent, NitroPoint, PetFigureData, RoomChatSettings, RoomChatSettingsEvent, RoomDragEvent, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomSessionChatEvent, RoomUserData, SystemChatStyleEnum, TextureUtils, Vector3d } from '@nitrots/nitro-renderer'; import { AvatarFigurePartType, AvatarScaleType, AvatarSetType, GetGuestRoomResultEvent, NitroPoint, PetFigureData, RoomChatSettings, RoomChatSettingsEvent, RoomDragEvent, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomSessionChatEvent, RoomUserData, SystemChatStyleEnum, TextureUtils, Vector3d } from '@nitrots/nitro-renderer';
import { useEffect, useMemo, useRef, useState } from 'react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { ChatBubbleMessage, ChatEntryType, ChatHistoryCurrentDate, GetAvatarRenderManager, GetConfiguration, GetRoomEngine, GetRoomObjectScreenLocation, IRoomChatSettings, LocalizeText, PlaySound, RoomChatFormatter } from '../../../api'; import { ChatBubbleMessage, ChatEntryType, ChatHistoryCurrentDate, GetAvatarRenderManager, GetConfiguration, GetRoomEngine, GetRoomObjectScreenLocation, IRoomChatSettings, LocalizeText, PlaySound, RoomChatFormatter } from '../../../api';
import { useMessageEvent, useRoomEngineEvent, useRoomSessionManagerEvent } from '../../events'; import { useMessageEvent, useRoomEngineEvent, useRoomSessionManagerEvent } from '../../events';
import { useRoom } from '../useRoom'; import { useRoom } from '../useRoom';
@ -22,6 +22,7 @@ const useChatWidgetState = () =>
const { roomSession = null } = useRoom(); const { roomSession = null } = useRoom();
const { addChatEntry } = useChatHistory(); const { addChatEntry } = useChatHistory();
const isDisposed = useRef(false); const isDisposed = useRef(false);
const pendingChats = useRef<ChatBubbleMessage[]>([]);
const getScrollSpeed = useMemo(() => const getScrollSpeed = useMemo(() =>
{ {
@ -95,7 +96,7 @@ const useChatWidgetState = () =>
return existing; return existing;
} }
const removeHiddenChats = () => const removeHiddenChats = useCallback(() =>
{ {
setChatMessages(prevValue => setChatMessages(prevValue =>
{ {
@ -108,7 +109,7 @@ const useChatWidgetState = () =>
return prevValue; return prevValue;
}) })
} }, []);
const moveAllChatsUp = (amount: number) => const moveAllChatsUp = (amount: number) =>
{ {
@ -248,6 +249,7 @@ const useChatWidgetState = () =>
color); color);
setChatMessages(prevValue => [ ...prevValue, chatMessage ]); setChatMessages(prevValue => [ ...prevValue, chatMessage ]);
pendingChats?.current?.push(chatMessage);
addChatEntry({ id: -1, entityId: userData.roomIndex, name: username, imageUrl, style: styleId, chatType: chatType, entityType: userData.type, message: formattedText, timestamp: ChatHistoryCurrentDate(), type: ChatEntryType.TYPE_CHAT, roomId: roomSession.roomId, color }); addChatEntry({ id: -1, entityId: userData.roomIndex, name: username, imageUrl, style: styleId, chatType: chatType, entityType: userData.type, message: formattedText, timestamp: ChatHistoryCurrentDate(), type: ChatEntryType.TYPE_CHAT, roomId: roomSession.roomId, color });
}); });
@ -286,7 +288,7 @@ const useChatWidgetState = () =>
} }
}, []); }, []);
return { chatMessages, setChatMessages, chatSettings, getScrollSpeed, removeHiddenChats, moveAllChatsUp }; return { chatMessages, setChatMessages, chatSettings, getScrollSpeed, removeHiddenChats, moveAllChatsUp, pendingChats };
} }
export const useChatWidget = useChatWidgetState; export const useChatWidget = useChatWidgetState;